#ifndef lint static char Xrcsid[] = "$XConsortium: Toggle.c,v 1.15 89/12/11 15:22:59 kit Exp $"; #endif /* lint */ /* * Copyright 1989 Massachusetts Institute of Technology * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of M.I.T. not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. M.I.T. makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T. * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ /* * Toggle.c - Toggle button widget * * Author: Chris D. Peterson * MIT X Consortium * kit@expo.lcs.mit.edu * * Date: January 12, 1989 * */ #include #include #include #include <./Xaw3_1XawInit.h> #include #include <./Xaw3_1ToggleP.h> /**************************************************************** * * Full class record constant * ****************************************************************/ /* Private Data */ /* This is a hack, see the comments in ClassInit(). */ extern XtActionList xaw_command_actions_list; /* * The order of toggle and notify are important, as the state has * to be set when we call the notify proc. */ static char defaultTranslations[] = ": highlight(Always) \n\ : unhighlight() \n\ ,: toggle() notify()"; #define offset(field) XtOffset(ToggleWidget, field) static XtResource resources[] = { {XtNstate, XtCState, XtRBoolean, sizeof(Boolean), offset(command.set), XtRString, "off"}, {XtNradioGroup, XtCWidget, XtRWidget, sizeof(Widget), offset(toggle.widget), XtRWidget, (caddr_t) NULL }, {XtNradioData, XtCRadioData, XtRPointer, sizeof(caddr_t), offset(toggle.radio_data), XtRPointer, (caddr_t) NULL }, }; #undef offset /* Action proceedures retrieved from the command widget */ static void Toggle(), Initialize(), Notify(), ToggleSet(); static void ToggleDestroy(), ClassInit(); static Boolean SetValues(); /* Functions for handling the Radio Group. */ static RadioGroup * GetRadioGroup(); static void CreateRadioGroup(), AddToRadioGroup(), TurnOffRadioSiblings(); static void RemoveFromRadioGroup(); static XtActionsRec actionsList[] = { {"toggle", Toggle}, {"notify", Notify}, {"set", ToggleSet}, }; #define SuperClass ((CommandWidgetClass)&commandClassRec) ToggleClassRec toggleClassRec = { { (WidgetClass) SuperClass, /* superclass */ "Toggle", /* class_name */ sizeof(ToggleRec), /* size */ ClassInit, /* class_initialize */ NULL, /* class_part_initialize */ FALSE, /* class_inited */ Initialize, /* initialize */ NULL, /* initialize_hook */ XtInheritRealize, /* realize */ actionsList, /* actions */ XtNumber(actionsList), /* num_actions */ resources, /* resources */ XtNumber(resources), /* resource_count */ NULLQUARK, /* xrm_class */ FALSE, /* compress_motion */ TRUE, /* compress_exposure */ TRUE, /* compress_enterleave */ FALSE, /* visible_interest */ NULL, /* destroy */ XtInheritResize, /* resize */ XtInheritExpose, /* expose */ SetValues, /* set_values */ NULL, /* set_values_hook */ XtInheritSetValuesAlmost, /* set_values_almost */ NULL, /* get_values_hook */ NULL, /* accept_focus */ XtVersion, /* version */ NULL, /* callback_private */ defaultTranslations, /* tm_table */ XtInheritQueryGeometry, /* query_geometry */ XtInheritDisplayAccelerator, /* display_accelerator */ NULL /* extension */ }, /* CoreClass fields initialization */ { XtInheritChangeSensitive /* change_sensitive */ }, /* SimpleClass fields initialization */ { 0 /* field not used */ }, /* LabelClass fields initialization */ { 0 /* field not used */ }, /* CommmandClass fields initialization */ { NULL, /* Set Proceedure. */ NULL, /* Unset Proceedure. */ NULL /* extension. */ } /* ToggleClass fields initialization */ }; /* for public consumption */ WidgetClass toggleWidgetClass = (WidgetClass) &toggleClassRec; /**************************************************************** * * Private Procedures * ****************************************************************/ static void ClassInit() { XtActionList actions; Cardinal i; ToggleWidgetClass class = (ToggleWidgetClass) toggleWidgetClass; XawInitializeWidgetSet(); /* actions = SuperClass->core_class.actions; */ /* The actions table should really be retrieved from the toggle widget's * Superclass, but this information is munged by the R3 intrinsics so the * I have hacked the Athena command widget to export its action table * as a global variable. * * Chris D. Peterson 12/28/88. */ actions = xaw_command_actions_list; /* * Find the set and unset actions in the command widget's action table. */ for (i = 0 ; i < SuperClass->core_class.num_actions ; i++) { if (streq(actions[i].string, "set")) class->toggle_class.Set = actions[i].proc; if (streq(actions[i].string, "unset")) class->toggle_class.Unset = actions[i].proc; if ( (class->toggle_class.Set != NULL) && (class->toggle_class.Unset != NULL) ) return; } /* We should never get here. */ if (class->toggle_class.Set == NULL) XtWarning( "Toggle could not find action Proceedure Set() in the Command Widget."); if (class->toggle_class.Unset == NULL) XtWarning( "Toggle could not find action Proceedure Unset() in the Command Widget."); XtError("Aborting, due to errors in Toggle widget."); } static void Initialize(request, new) Widget request, new; { ToggleWidget tw = (ToggleWidget) new; ToggleWidget tw_req = (ToggleWidget) request; tw->toggle.radio_group = NULL; if (tw->toggle.radio_data == NULL) tw->toggle.radio_data = (caddr_t) new->core.name; if (tw->toggle.widget != NULL) { if ( GetRadioGroup(tw->toggle.widget) == NULL) CreateRadioGroup(new, tw->toggle.widget); else AddToRadioGroup( GetRadioGroup(tw->toggle.widget), new); } XtAddCallback(new, XtNdestroyCallback, ToggleDestroy, NULL); /* * Command widget assumes that the widget is unset, so we only * have to handle the case where it needs to be set. * * If this widget is in a radio group then it may cause another * widget to be unset, thus calling the notify proceedure. * * I want to set the toggle if the user set the state to "On" in * the resource group, reguardless of what my ancestors did. */ if (tw_req->command.set) ToggleSet(new, NULL, NULL, 0); } /************************************************************ * * Action Procedures * ************************************************************/ /* ARGSUSED */ static void ToggleSet(w,event,params,num_params) Widget w; XEvent *event; String *params; /* unused */ Cardinal *num_params; /* unused */ { ToggleWidgetClass class = (ToggleWidgetClass) w->core.widget_class; TurnOffRadioSiblings(w); class->toggle_class.Set(w, event, NULL, 0); } /* ARGSUSED */ static void Toggle(w,event,params,num_params) Widget w; XEvent *event; String *params; /* unused */ Cardinal *num_params; /* unused */ { ToggleWidget tw = (ToggleWidget)w; ToggleWidgetClass class = (ToggleWidgetClass) w->core.widget_class; if (tw->command.set) class->toggle_class.Unset(w, event, NULL, 0); else ToggleSet(w, event, params, num_params); } /* ARGSUSED */ static void Notify(w,event,params,num_params) Widget w; XEvent *event; String *params; /* unused */ Cardinal *num_params; /* unused */ { ToggleWidget tw = (ToggleWidget) w; XtCallCallbacks(w, XtNcallback, tw->command.set); } /************************************************************ * * Set specified arguments into widget * ***********************************************************/ /* ARGSUSED */ static Boolean SetValues (current, request, new) Widget current, request, new; { ToggleWidget oldtw = (ToggleWidget) current; ToggleWidget tw = (ToggleWidget) new; if (oldtw->toggle.widget != tw->toggle.widget) XawToggleChangeRadioGroup(new, tw->toggle.widget); if (oldtw->command.set != tw->command.set) { tw->command.set = oldtw->command.set; Toggle(new, NULL, NULL, 0); /* Does a redisplay. */ } return(FALSE); } /* Function Name: ToggleDestroy * Description: Destroy Callback for toggle widget. * Arguments: w - the toggle widget that is being destroyed. * junk, grabage - not used. * Returns: none. */ /* ARGSUSED */ static void ToggleDestroy(w, junk, garbage) Widget w; caddr_t junk, garbage; { RemoveFromRadioGroup(w); } /************************************************************ * * Below are all the private proceedures that handle * radio toggle buttons. * ************************************************************/ /* Function Name: GetRadioGroup * Description: Gets the radio group associated with a give toggle * widget. * Arguments: w - the toggle widget who's radio group we are getting. * Returns: the radio group associated with this toggle group. */ static RadioGroup * GetRadioGroup(w) Widget w; { ToggleWidget tw = (ToggleWidget) w; if (tw == NULL) return(NULL); return( tw->toggle.radio_group ); } /* Function Name: CreateRadioGroup * Description: Creates a radio group. give two widgets. * Arguments: w1, w2 - the toggle widgets to add to the radio group. * Returns: none. * * NOTE: A pointer to the group is added to each widget's radio_group * field. */ static void CreateRadioGroup(w1, w2) Widget w1, w2; { char error_buf[BUFSIZ]; ToggleWidget tw1 = (ToggleWidget) w1; ToggleWidget tw2 = (ToggleWidget) w2; if ( (tw1->toggle.radio_group != NULL) || (tw2->toggle.radio_group != NULL) ) { sprintf(error_buf, "%s %s", "Toggle Widget Error - Attempting", "to create a new toggle group, when one already exists."); XtWarning(error_buf); } AddToRadioGroup( NULL, w1 ); AddToRadioGroup( GetRadioGroup(w1), w2 ); } /* Function Name: AddToRadioGroup * Description: Adds a toggle to the radio group. * Arguments: group - any element of the radio group the we are adding to. * w - the new toggle widget to add to the group. * Returns: none. */ static void AddToRadioGroup(group, w) RadioGroup * group; Widget w; { ToggleWidget tw = (ToggleWidget) w; RadioGroup * local; local = (RadioGroup *) XtMalloc( sizeof(RadioGroup) ); local->widget = w; tw->toggle.radio_group = local; if (group == NULL) { /* Creating new group. */ group = local; group->next = NULL; group->prev = NULL; return; } local->prev = group; /* Adding to previous group. */ if ((local->next = group->next) != NULL) local->next->prev = local; group->next = local; } /* Function Name: TurnOffRadioSiblings * Description: Deactivates all radio siblings. * Arguments: widget - a toggle widget. * Returns: none. */ static void TurnOffRadioSiblings(w) Widget w; { RadioGroup * group; ToggleWidgetClass class = (ToggleWidgetClass) w->core.widget_class; if ( (group = GetRadioGroup(w)) == NULL) /* Punt if there is no group */ return; /* Go to the top of the group. */ for ( ; group->prev != NULL ; group = group->prev ); while ( group != NULL ) { ToggleWidget local_tog = (ToggleWidget) group->widget; if ( local_tog->command.set ) { class->toggle_class.Unset(group->widget, NULL, NULL, 0); Notify( group->widget, NULL, NULL, 0); } group = group->next; } } /* Function Name: RemoveFromRadioGroup * Description: Removes a toggle from a RadioGroup. * Arguments: w - the toggle widget to remove. * Returns: none. */ static void RemoveFromRadioGroup(w) Widget w; { RadioGroup * group = GetRadioGroup(w); if (group != NULL) { if (group->prev != NULL) (group->prev)->next = group->next; if (group->next != NULL) (group->next)->prev = group->prev; XtFree(group); } } /************************************************************ * * Public Routines * ************************************************************/ /* Function Name: XawToggleChangeRadioGroup * Description: Allows a toggle widget to change radio groups. * Arguments: w - The toggle widget to change groups. * radio_group - any widget in the new group. * Returns: none. */ void XawToggleChangeRadioGroup(w, radio_group) Widget w, radio_group; { ToggleWidget tw = (ToggleWidget) w; RemoveFromRadioGroup(w); /* * If the toggle that we are about to add is set then we will * unset all toggles in the new radio group. */ if ( tw->command.set && radio_group != NULL ) XawToggleUnsetCurrent(radio_group); AddToRadioGroup( GetRadioGroup(radio_group), w ); } /* Function Name: XawToggleGetCurrent * Description: Returns the RadioData associated with the toggle * widget that is currently active in a toggle group. * Arguments: w - any toggle widget in the toggle group. * Returns: The XtNradioData associated with the toggle widget. */ caddr_t XawToggleGetCurrent(w) Widget w; { RadioGroup * group; if ( (group = GetRadioGroup(w)) == NULL) return(NULL); for ( ; group->prev != NULL ; group = group->prev); while ( group != NULL ) { ToggleWidget local_tog = (ToggleWidget) group->widget; if ( local_tog->command.set ) return( local_tog->toggle.radio_data ); group = group->next; } return(NULL); } /* Function Name: XawToggleSetCurrent * Description: Sets the Toggle widget associated with the * radio_data specified. * Arguments: radio_group - any toggle widget in the toggle group. * radio_data - radio data of the toggle widget to set. * Returns: none. */ void XawToggleSetCurrent(radio_group, radio_data) Widget radio_group; caddr_t radio_data; { RadioGroup * group; ToggleWidget local_tog; /* Special case case of no radio group. */ if ( (group = GetRadioGroup(radio_group)) == NULL) { local_tog = (ToggleWidget) radio_group; if ( (local_tog->toggle.radio_data == radio_data) ) if (!local_tog->command.set) { ToggleSet((Widget) local_tog, NULL, NULL, 0); Notify((Widget) local_tog, NULL, NULL, 0); } return; } /* * find top of radio_roup */ for ( ; group->prev != NULL ; group = group->prev); /* * search for matching radio data. */ while ( group != NULL ) { local_tog = (ToggleWidget) group->widget; if ( (local_tog->toggle.radio_data == radio_data) ) { if (!local_tog->command.set) { /* if not already set. */ ToggleSet((Widget) local_tog, NULL, NULL, 0); Notify((Widget) local_tog, NULL, NULL, 0); } return; /* found it, done */ } group = group->next; } } /* Function Name: XawToggleUnsetCurrent * Description: Unsets all Toggles in the radio_group specified. * Arguments: radio_group - any toggle widget in the toggle group. * Returns: none. */ void XawToggleUnsetCurrent(radio_group) Widget radio_group; { ToggleWidgetClass class; ToggleWidget local_tog = (ToggleWidget) radio_group; /* Special Case no radio group. */ if (local_tog->command.set) { class = (ToggleWidgetClass) local_tog->core.widget_class; class->toggle_class.Unset(radio_group, NULL, NULL, 0); Notify(radio_group, NULL, NULL, 0); } if ( GetRadioGroup(radio_group) == NULL) return; TurnOffRadioSiblings(radio_group); }