/* * @OPENGROUP_COPYRIGHT@ * COPYRIGHT NOTICE * Copyright (c) 1990, 1991, 1992, 1993 Open Software Foundation, Inc. * Copyright (c) 1996, 1997, 1998, 1999, 2000 The Open Group * ALL RIGHTS RESERVED (MOTIF). See the file named COPYRIGHT.MOTIF for * the full copyright text. * * This software is subject to an open license. It may only be * used on, with or for operating systems which are themselves open * source systems. You must contact The Open Group for a license * allowing distribution and sublicensing of this software on, with, * or for operating systems which are not Open Source programs. * * See http://www.opengroup.org/openmotif/license for full * details of the license agreement. Any use, reproduction, or * distribution of the program constitutes recipient's acceptance of * this agreement. * * EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS * PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY * WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY * OR FITNESS FOR A PARTICULAR PURPOSE * * EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT * NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE * EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. */ /* * HISTORY */ #ifdef REV_INFO #ifndef lint static char rcsid[] = "$TOG: ToggleB.c /main/43 1999/12/06 18:09:38 samborn $" #endif #endif /* (c) Copyright 1989, DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS. */ /* (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 HEWLETT-PACKARD COMPANY */ #include #include "XmI.h" #include #include #include #include #include #include #include #include #include #include #include #include "ColorI.h" #include "LabelI.h" #include "MenuProcI.h" #include "MenuStateI.h" #include "PrimitiveI.h" #include "RepTypeI.h" #include "TravActI.h" #include "TraversalI.h" #include "UniqueEvnI.h" #define XmINVALID_TYPE 255 /* default flag for IndicatorType */ #define XmINVALID_BOOLEAN 85 /* default flag for VisibleWhenOff */ #define XmINVALID_PIXEL ((Pixel) -1) /* default flag for unselectColor */ #define MIN_GLYPH_SIZE 5 /* Threshold for rendering glyphs. */ #define PixmapOn(w) ((w)->toggle.on_pixmap) #define PixmapOff(w) ((w)->label.pixmap) #define PixmapInd(w) ((w)->toggle.indeterminate_pixmap) #define PixmapInsenOn(w) ((w)->toggle.insen_pixmap) #define PixmapInsenOff(w) ((w)->label.pixmap_insen) #define PixmapInsenInd(w) ((w)->toggle.indeterminate_insensitive_pixmap) #define IsNull(p) ((p) == XmUNSPECIFIED_PIXMAP) #define IsOn(w) ((w)->toggle.visual_set) #define IsOneOfMany(ind_type) (((ind_type) == XmONE_OF_MANY) || \ ((ind_type) == XmONE_OF_MANY_ROUND) || \ ((ind_type) == XmONE_OF_MANY_DIAMOND)) /* Constants used to decompose XmNindicatorOn values. */ #define XmINDICATOR_BOX_MASK 0x0f #define XmINDICATOR_GLYPH_MASK 0xf0 /* The indicator value should already have been normalized! */ #define DRAW3DBOX(ind_on) ((ind_on) & XmINDICATOR_3D_BOX) #define DRAWFLATBOX(ind_on) ((ind_on) & XmINDICATOR_FLAT_BOX) #define DRAWBOX(ind_on) ((ind_on) & XmINDICATOR_BOX_MASK) #define DRAWCHECK(ind_on) ((ind_on) & XmINDICATOR_CHECK_GLYPH) #define DRAWCROSS(ind_on) ((ind_on) & XmINDICATOR_CROSS_GLYPH) #define DRAWGLYPH(ind_on) ((ind_on) & XmINDICATOR_GLYPH_MASK) /******** Static Function Declarations ********/ static void ClassInitialize( void ) ; static void ClassPartInitialize( WidgetClass wc) ; static void InitializePrehook( Widget req, Widget new_w, ArgList args, Cardinal *num_args) ; static void InitializePosthook( Widget req, Widget new_w, ArgList args, Cardinal *num_args) ; static void SetAndDisplayPixmap( XmToggleButtonWidget tb, XEvent *event, Region region) ; static void Help( Widget wid, XEvent *event, String *params, Cardinal *num_params) ; static void ToggleButtonCallback( XmToggleButtonWidget data, unsigned int reason, unsigned int value, XEvent *event) ; static void Leave( Widget wid, XEvent *event, String *params, Cardinal *num_params) ; static void Enter( Widget wid, XEvent *event, String *params, Cardinal *num_params) ; static void Arm( Widget wid, XEvent *event, String *params, Cardinal *num_params) ; static void Select( Widget wid, XEvent *event, String *params, Cardinal *num_params) ; static void Disarm( Widget wid, XEvent *event, String *params, Cardinal *num_params) ; static void ArmAndActivate( Widget wid, XEvent *event, String *params, Cardinal *num_params) ; static void BtnDown( Widget wid, XEvent *event, String *params, Cardinal *num_params) ; static void BtnUp( Widget wid, XEvent *event, String *params, Cardinal *num_params) ; static void GetGC( XmToggleButtonWidget tw) ; static void Initialize( Widget rw, Widget nw, ArgList args, Cardinal *num_args) ; static void Destroy( Widget wid) ; static void DrawToggle( XmToggleButtonWidget w) ; static void BorderHighlight( Widget wid) ; static void BorderUnhighlight( Widget wid) ; static void KeySelect( Widget wid, XEvent *event, String *param, Cardinal *num_param) ; static void ComputeSpace( XmToggleButtonWidget tb) ; static void Redisplay( Widget w, XEvent *event, Region region) ; static void Resize( Widget w) ; static Boolean SetValuesPrehook( Widget current, Widget request, Widget new_w, ArgList args, Cardinal *num_args) ; static Boolean SetValues( Widget current, Widget request, Widget new_w, ArgList args, Cardinal *num_args) ; static void DrawToggleShadow( XmToggleButtonWidget tb) ; static void DrawToggleLabel( XmToggleButtonWidget tb) ; static void DrawEtchedInMenu( XmToggleButtonWidget tb) ; static void SetToggleSize( XmToggleButtonWidget newtb) ; static void NextState(unsigned char *state); static void DrawBox( XmToggleButtonWidget w, GC top_gc, GC bot_gc, GC fillgc, int x, int y, int edge, Dimension margin ); static void DefaultSelectColor(Widget widget, int offset, XrmValue *value); static unsigned char NormalizeIndOn(XmToggleButtonWidget tb); static unsigned char NormalizeIndType(XmToggleButtonWidget tb); static void TB_FixTearoff( XmToggleButtonWidget tb); /******** End Static Function Declarations ********/ /*************************************<->************************************* * * * Description: default translation table for class: ToggleButton * ----------- * * Matches events with string descriptors for internal routines. * *************************************<->***********************************/ static XtTranslations default_parsed; #define defaultTranslations _XmToggleB_defaultTranslations static XtTranslations menu_parsed; #define menuTranslations _XmToggleB_menuTranslations /*************************************<->************************************* * * * Description: action list for class: ToggleButton * ----------- * * Matches string descriptors with internal routines. * *************************************<->***********************************/ static XtActionsRec actionsList[] = { {"Arm", Arm }, {"ArmAndActivate", ArmAndActivate }, {"Disarm", Disarm }, {"Select", Select }, {"Enter", Enter }, {"Leave", Leave }, {"BtnDown", BtnDown }, {"BtnUp", BtnUp }, {"ButtonTakeFocus", _XmButtonTakeFocus }, {"MenuButtonTakeFocus", _XmMenuButtonTakeFocus }, {"MenuButtonTakeFocusUp", _XmMenuButtonTakeFocusUp }, {"KeySelect", KeySelect }, {"Help", Help}, }; /*************************************<->************************************* * * * Description: resource list for class: ToggleButton * ----------- * * Provides default resource settings for instances of this class. * To get full set of default settings, examine resouce list of super * classes of this class. * *************************************<->***********************************/ #define Offset(field) (XtOffsetOf(XmToggleButtonRec, field)) static XtResource resources[] = { { XmNindicatorSize, XmCIndicatorSize, XmRVerticalDimension, sizeof(Dimension), Offset(toggle.indicator_dim), XmRImmediate, (XtPointer) XmINVALID_DIMENSION }, { XmNindicatorType, XmCIndicatorType, XmRIndicatorType, sizeof(unsigned char), Offset(toggle.ind_type), XmRImmediate, (XtPointer) XmINVALID_TYPE }, { XmNvisibleWhenOff, XmCVisibleWhenOff, XmRBoolean, sizeof(Boolean), Offset(toggle.visible), XmRImmediate, (XtPointer) XmINVALID_BOOLEAN }, { XmNspacing, XmCSpacing, XmRHorizontalDimension, sizeof(Dimension), Offset(toggle.spacing), XmRImmediate, (XtPointer) 4 }, { XmNselectPixmap, XmCSelectPixmap, XmRDynamicPixmap, sizeof(Pixmap), Offset(toggle.on_pixmap), XmRImmediate, (XtPointer) XmUNSPECIFIED_PIXMAP }, { XmNselectInsensitivePixmap, XmCSelectInsensitivePixmap, XmRDynamicPixmap, sizeof(Pixmap), Offset(toggle.insen_pixmap), XmRImmediate, (XtPointer) XmUNSPECIFIED_PIXMAP }, { XmNset, XmCSet, XmRSet, sizeof(unsigned char), Offset(toggle.set), XmRImmediate, (XtPointer) XmUNSET }, { XmNindicatorOn, XmCIndicatorOn, XmRIndicatorOn, sizeof (unsigned char), Offset(toggle.ind_on), XmRImmediate, (XtPointer) XmINDICATOR_FILL }, { XmNfillOnSelect, XmCFillOnSelect, XmRBoolean, sizeof(Boolean), Offset(toggle.fill_on_select), XmRImmediate, (XtPointer) XmINVALID_BOOLEAN }, { XmNselectColor, XmCSelectColor, XmRSelectColor, sizeof(Pixel), Offset(toggle.select_color), XmRCallProc, (XtPointer) DefaultSelectColor }, { XmNvalueChangedCallback, XmCValueChangedCallback, XmRCallback, sizeof (XtCallbackList), Offset(toggle.value_changed_CB), XmRPointer, (XtPointer)NULL }, { XmNarmCallback, XmCArmCallback, XmRCallback, sizeof(XtCallbackList), Offset(toggle.arm_CB), XmRPointer, (XtPointer)NULL }, { XmNdisarmCallback, XmCDisarmCallback, XmRCallback, sizeof (XtCallbackList), Offset(toggle.disarm_CB), XmRPointer, (XtPointer)NULL }, { XmNtraversalOn, XmCTraversalOn, XmRBoolean, sizeof(Boolean), Offset(primitive.traversal_on), XmRImmediate, (XtPointer) True }, { XmNhighlightThickness, XmCHighlightThickness, XmRHorizontalDimension, sizeof(Dimension), Offset(primitive.highlight_thickness), XmRCallProc, (XtPointer) _XmSetThickness }, { XmNtoggleMode, XmCToggleMode, XmRToggleMode, sizeof(unsigned char), Offset(toggle.toggle_mode), XmRImmediate, (XtPointer) XmTOGGLE_BOOLEAN }, { XmNindeterminatePixmap, XmCIndeterminatePixmap, XmRDynamicPixmap, sizeof(Pixmap), Offset(toggle.indeterminate_pixmap), XmRImmediate, (XtPointer) XmUNSPECIFIED_PIXMAP }, { XmNindeterminateInsensitivePixmap, XmCIndeterminateInsensitivePixmap, XmRDynamicPixmap, sizeof(Pixmap), Offset(toggle.indeterminate_insensitive_pixmap), XmRImmediate, (XtPointer) XmUNSPECIFIED_PIXMAP }, { XmNunselectColor, XmCUnselectColor, XmRPixel, sizeof(Pixel), Offset(toggle.unselect_color), XmRImmediate, (XtPointer) XmINVALID_PIXEL }, { XmNdetailShadowThickness, XmCShadowThickness, XmRHorizontalDimension, sizeof(Dimension), Offset(toggle.detail_shadow_thickness), XmRCallProc, (XtPointer) _XmSetThickness } }; /* Definition for resources that need special processing in get values */ static XmSyntheticResource syn_resources[] = { { XmNspacing, sizeof(Dimension), Offset(toggle.spacing), XmeFromHorizontalPixels, XmeToHorizontalPixels }, { XmNindicatorSize, sizeof(Dimension), Offset(toggle.indicator_dim), XmeFromVerticalPixels, XmeToVerticalPixels }, { XmNdetailShadowThickness, sizeof(Dimension), Offset(toggle.detail_shadow_thickness), XmeFromHorizontalPixels, XmeToHorizontalPixels } }; #undef Offset /*************************************<->************************************* * * * Description: global class record for instances of class: ToggleButton * ----------- * * Defines default field settings for this class record. * *************************************<->***********************************/ static XmBaseClassExtRec toggleBBaseClassExtRec = { NULL, /* Next extension */ NULLQUARK, /* record type XmQmotif */ XmBaseClassExtVersion, /* version */ sizeof(XmBaseClassExtRec), /* size */ InitializePrehook, /* initialize prehook */ SetValuesPrehook, /* set_values prehook */ InitializePosthook, /* initialize posthook */ XmInheritSetValuesPosthook, /* set_values posthook */ XmInheritClass, /* secondary class */ XmInheritSecObjectCreate, /* creation proc */ XmInheritGetSecResData, /* getSecResData */ {0}, /* fast subclass */ XmInheritGetValuesPrehook, /* get_values prehook */ XmInheritGetValuesPosthook, /* get_values posthook */ (XtWidgetClassProc)NULL, /* classPartInitPrehook */ (XtWidgetClassProc)NULL, /* classPartInitPosthook*/ NULL, /* ext_resources */ NULL, /* compiled_ext_resources*/ 0, /* num_ext_resources */ FALSE, /* use_sub_resources */ XmInheritWidgetNavigable, /* widgetNavigable */ XmInheritFocusChange, /* focusChange */ }; externaldef(xmtogglebuttonclassrec) XmToggleButtonClassRec xmToggleButtonClassRec = { { /* superclass */ (WidgetClass) &xmLabelClassRec, /* class_name */ "XmToggleButton", /* widget_size */ sizeof(XmToggleButtonRec), /* class_initialize */ ClassInitialize, /* class_part_init */ ClassPartInitialize, /* class_inited */ FALSE, /* initialize */ Initialize, /* initialize_hook */ (XtArgsProc)NULL, /* realize */ XmInheritRealize, /* actions */ actionsList, /* num_actions */ XtNumber(actionsList), /* resources */ resources, /* num_resources */ XtNumber(resources), /* xrm_class */ NULLQUARK, /* compress_motion */ TRUE, /* compress_exposure */ XtExposeCompressMaximal, /* compress_enterlv */ TRUE, /* visible_interest */ FALSE, /* destroy */ Destroy, /* resize */ Resize, /* expose */ Redisplay, /* set_values */ SetValues, /* set_values_hook */ (XtArgsFunc)NULL, /* set_values_almost */ XtInheritSetValuesAlmost, /* get_values_hook */ (XtArgsProc)NULL, /* accept_focus */ (XtAcceptFocusProc)NULL, /* version */ XtVersion, /* callback_private */ NULL, /* tm_table */ NULL, /* query_geometry */ XtInheritQueryGeometry, /* display_accelerator*/ (XtStringProc)NULL, /* extension record */ (XtPointer)&toggleBBaseClassExtRec, }, { /* Primitive border_highlight */ BorderHighlight, /* Primitive border_unhighlight */ BorderUnhighlight, /* translations */ XtInheritTranslations, /* arm_and_activate */ ArmAndActivate, /* syn resources */ syn_resources, /* num syn_resources */ XtNumber(syn_resources), /* extension */ NULL, }, { /* SetOverrideCallback */ XmInheritWidgetProc, /* menu procedures */ XmInheritMenuProc, /* menu traversal xlation */ XtInheritTranslations, /* extension */ NULL, }, { /* extension */ (XtPointer) NULL, } }; externaldef(xmtogglebuttonwidgetclass) WidgetClass xmToggleButtonWidgetClass = (WidgetClass)&xmToggleButtonClassRec; /* Menu Savvy trait record */ static XmMenuSavvyTraitRec MenuSavvyRecord = { /* version: */ -1, NULL, NULL, NULL, _XmCBNameValueChanged, }; /*************************************<->************************************* * * ClassInitialize * *************************************<->***********************************/ static void ClassInitialize( void ) { /* Parse the various translation tables. */ default_parsed = XtParseTranslationTable(defaultTranslations); menu_parsed = XtParseTranslationTable(menuTranslations); /* Set up base class extension quark */ toggleBBaseClassExtRec.record_type = XmQmotif; } /***************************************************************************** * * ClassPartInitialize * Set up fast subclassing for the widget. * ****************************************************************************/ static void ClassPartInitialize( WidgetClass wc ) { _XmFastSubclassInit (wc, XmTOGGLE_BUTTON_BIT); /* Install the menu savvy trait record, copying fields from XmLabel */ _XmLabelCloneMenuSavvy (wc, &MenuSavvyRecord); } /************************************************************ * * InitializePrehook * * Put the proper translations in core_class tm_table so that * the data is massaged correctly * ************************************************************/ /*ARGSUSED*/ static void InitializePrehook( Widget req, /* unused */ Widget new_w, ArgList args, /* unused */ Cardinal *num_args ) /* unused */ { unsigned char type; XmMenuSystemTrait menuSTrait; XmToggleButtonWidget bw = (XmToggleButtonWidget) new_w ; menuSTrait = (XmMenuSystemTrait) XmeTraitGet((XtPointer) XtClass(XtParent(new_w)), XmQTmenuSystem); _XmSaveCoreClassTranslations (new_w); if (menuSTrait != NULL) type = menuSTrait->type(XtParent(new_w)); else type = XmWORK_AREA; _XmProcessLock(); if ((type == XmMENU_PULLDOWN) || (type == XmMENU_POPUP)) new_w->core.widget_class->core_class.tm_table = (String) menu_parsed; else new_w->core.widget_class->core_class.tm_table = (String) default_parsed; _XmProcessUnlock(); /* CR 2990: Use XmNbuttonFontList as the default font. */ if (bw->label.font == NULL) bw->label.font = XmeGetDefaultRenderTable (new_w, XmBUTTON_FONTLIST); } /************************************************************ * * InitializePosthook * * restore core class translations * ************************************************************/ /*ARGSUSED*/ static void InitializePosthook( Widget req, /* unused */ Widget new_w, ArgList args, /* unused */ Cardinal *num_args ) /* unused */ { _XmRestoreCoreClassTranslations (new_w); } /********************************************************************* * * redisplayPixmap * does the apropriate calculations based on the toggle button's * current pixmap and calls label's Redisplay routine. * * This routine was added to fix CR 4839 and CR 4838 * D. Rand 7/6/92 * ***********************************************************************/ static void redisplayPixmap(XmToggleButtonWidget tb, XEvent *event, Region region) { Pixmap todo; unsigned int onH = 0, onW = 0; int w, h; int x, y, offset; short saveY; unsigned short saveWidth, saveHeight; offset = tb->primitive.highlight_thickness + tb->primitive.shadow_thickness; x = offset + tb->label.margin_width + tb->label.margin_left; y = offset + tb->label.margin_height + tb->label.margin_top; w = XtWidth(tb) - x - offset - tb->label.margin_right - tb->label.margin_width; ASSIGN_MAX(w, 0); h = XtHeight(tb) - y - offset - tb->label.margin_bottom - tb->label.margin_height; ASSIGN_MAX(h, 0); XClearArea(XtDisplay(tb), XtWindow(tb), x, y, w, h, False); todo = tb->label.pixmap; if ((! XtIsSensitive((Widget) tb)) && tb->label.pixmap_insen) todo = tb->label.pixmap_insen; if (! IsNull(todo)) XmeGetPixmapData(XtScreen(tb), todo, NULL, NULL, NULL, NULL, NULL, NULL, &onW, &onH); saveY = Lab_TextRect_y(tb); saveWidth = Lab_TextRect_width(tb); saveHeight = Lab_TextRect_height(tb); h = (XtHeight(tb) - onH) / 2; Lab_TextRect_y(tb) = MAX(h, 0); Lab_TextRect_height(tb) = onH; Lab_TextRect_width(tb) = onW; { XtExposeProc expose; _XmProcessLock(); expose = xmLabelClassRec.core_class.expose; _XmProcessUnlock(); (* expose) ((Widget) tb, event, region); } Lab_TextRect_y(tb) = saveY; Lab_TextRect_width(tb) = saveWidth; Lab_TextRect_height(tb) = saveHeight; } static void HandlePixmap(XmToggleButtonWidget tb, Pixmap pix, Pixmap insen_pix, XEvent * event, Region region) { if (XtIsSensitive((Widget) tb)) { if (! IsNull (pix)) { Pixmap tempPix = tb->label.pixmap; tb->label.pixmap = pix; redisplayPixmap(tb, event, region); tb->label.pixmap = tempPix; } else redisplayPixmap(tb, event, region); } else { if (! IsNull (insen_pix)) { Pixmap tempPix = tb->label.pixmap_insen; tb->label.pixmap_insen = insen_pix; redisplayPixmap(tb, event, region); tb->label.pixmap_insen = tempPix; } else redisplayPixmap(tb, event, region); } } /*********************************************************************** * * SetAndDisplayPixmap * Sets the appropriate on, off pixmap in label's pixmap field and * calls redisplayPixmap * ***********************************************************************/ static void SetAndDisplayPixmap( XmToggleButtonWidget tb, XEvent *event, Region region ) { if (tb->toggle.toggle_mode == XmTOGGLE_INDETERMINATE) { if (tb->toggle.visual_set == XmUNSET) HandlePixmap(tb, PixmapOff(tb), PixmapInsenOff(tb), event, region); else if (tb->toggle.visual_set == XmSET) HandlePixmap(tb, PixmapOn(tb), PixmapInsenOn(tb), event, region); else if (tb->toggle.visual_set == XmINDETERMINATE) HandlePixmap(tb, PixmapInd(tb), PixmapInsenInd(tb), event, region); } else { if (IsOn (tb) == XmSET) HandlePixmap(tb, PixmapOn(tb), PixmapInsenOn(tb), event, region); else redisplayPixmap(tb, event, region); } } /************************************************************************* * * Help * This routine is called if the user has made a help selection * on the widget. * ************************************************************************/ static void Help( Widget wid, XEvent *event, String *params, Cardinal *num_params ) { XmToggleButtonWidget tb = (XmToggleButtonWidget) wid ; Boolean is_menupane = Lab_IsMenupane(tb); XmMenuSystemTrait menuSTrait; menuSTrait = (XmMenuSystemTrait) XmeTraitGet((XtPointer) XtClass(XtParent(tb)), XmQTmenuSystem); if (is_menupane && menuSTrait != NULL) menuSTrait->buttonPopdown(XtParent(tb), event); _XmPrimitiveHelp( (Widget) tb, event, params, num_params); if (is_menupane && menuSTrait != NULL) menuSTrait->reparentToTearOffShell(XtParent(tb), event); } /************************************************************************* * * ToggleButtonCallback * This is the widget's application callback routine * *************************************************************************/ static void ToggleButtonCallback( XmToggleButtonWidget data, unsigned int reason, unsigned int value, XEvent *event ) { XmToggleButtonCallbackStruct temp; temp.reason = reason; temp.set = value; temp.event = event; switch (reason) { case XmCR_VALUE_CHANGED: XtCallCallbackList ((Widget) data, data->toggle.value_changed_CB, &temp); break; case XmCR_ARM: XtCallCallbackList ((Widget) data, data->toggle.arm_CB, &temp); break; case XmCR_DISARM: XtCallCallbackList ((Widget) data, data->toggle.disarm_CB, &temp); break; } } /* Update the toggle after an Enter or Leave action. */ static void ActionDraw(XmToggleButtonWidget w, XEvent *event, Boolean leave) { if (w->toggle.Armed) { /* CR 7301: We may have armed while outside the toggle. */ if (leave) w->toggle.visual_set = w->toggle.set; else if (w->toggle.toggle_mode == XmTOGGLE_INDETERMINATE) NextState(&w->toggle.visual_set); else IsOn(w) = (w->toggle.set == XmSET)? XmUNSET : XmSET; if (w->toggle.ind_on) DrawToggle(w); else { if (w->primitive.shadow_thickness > 0) DrawToggleShadow(w); if (w->toggle.fill_on_select && !Lab_IsPixmap(w)) DrawToggleLabel(w); } if (Lab_IsPixmap(w)) SetAndDisplayPixmap(w, event, NULL); } } /************************************************************************** * * Leave * This procedure is called when the mouse button is pressed and the * cursor moves out of the widget's window. This procedure is used * to change the visuals. * *************************************************************************/ static void Leave( Widget wid, XEvent *event, String *params, Cardinal *num_params ) { XmToggleButtonWidget w = (XmToggleButtonWidget) wid; if (Lab_IsMenupane(w)) { if (_XmGetInDragMode((Widget)w) && w->toggle.Armed && (/* !ActiveTearOff || */ event->xcrossing.mode == NotifyNormal)) { XmDisplay dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(wid)); Boolean etched_in = dpy->display.enable_etched_in_menu; w->toggle.Armed = FALSE; ((XmManagerWidget) XtParent(wid))->manager.active_child = NULL; if ((etched_in) && ((w->toggle.ind_on) || (!(w->toggle.ind_on) && !(w->toggle.fill_on_select)))) { DrawEtchedInMenu(w); if (w->toggle.ind_on) DrawToggle(w); } XmeClearBorder(XtDisplay (w), XtWindow (w), w->primitive.highlight_thickness, w->primitive.highlight_thickness, w->core.width - 2 * w->primitive.highlight_thickness, w->core.height - 2 * w->primitive.highlight_thickness, w->primitive.shadow_thickness); if (w->toggle.disarm_CB) { XFlush (XtDisplay (w)); ToggleButtonCallback(w, XmCR_DISARM, w->toggle.set, event); } } } else { _XmPrimitiveLeave( (Widget) w, event, params, num_params); ActionDraw(w, event, TRUE); } } /************************************************************************** * * Enter * This procedure is called when the mouse button is pressed and the * cursor reenters the widget's window. This procedure changes the visuals * accordingly. * **************************************************************************/ static void Enter( Widget wid, XEvent *event, String *params, Cardinal *num_params ) { XmToggleButtonWidget w = (XmToggleButtonWidget) wid ; if (Lab_IsMenupane(w)) { if ((((ShellWidget) XtParent(XtParent(w)))->shell.popped_up) && _XmGetInDragMode((Widget)w)) { XmDisplay dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(wid)); Boolean etched_in = dpy->display.enable_etched_in_menu; if (w->toggle.Armed) return; /* So KHelp event is delivered correctly */ _XmSetFocusFlag( XtParent(XtParent(w)), XmFOCUS_IGNORE, TRUE); XtSetKeyboardFocus(XtParent(XtParent(w)), (Widget)w); _XmSetFocusFlag( XtParent(XtParent(w)), XmFOCUS_IGNORE, FALSE); ((XmManagerWidget) XtParent(wid))->manager.active_child = wid; w->toggle.Armed = TRUE; if ((etched_in) && ((w->toggle.ind_on) || (!(w->toggle.ind_on) && !(w->toggle.fill_on_select)))) { DrawEtchedInMenu(w); if (w->toggle.ind_on) DrawToggle(w); } XmeDrawShadows (XtDisplay (w), XtWindow (w), w->primitive.top_shadow_GC, w->primitive.bottom_shadow_GC, w->primitive.highlight_thickness, w->primitive.highlight_thickness, w->core.width - 2 * w->primitive.highlight_thickness, w->core.height - 2 * w->primitive.highlight_thickness, w->primitive.shadow_thickness, etched_in ? XmSHADOW_IN : XmSHADOW_OUT); if (w->toggle.arm_CB) { XFlush (XtDisplay (w)); ToggleButtonCallback(w, XmCR_ARM, w->toggle.set, event); } } } else { _XmPrimitiveEnter( (Widget) w, event, params, num_params); ActionDraw(w, event, FALSE); } } static void NextState( unsigned char *state) { switch(*state) { case XmUNSET: *state = XmSET; break; case XmSET: *state = XmINDETERMINATE; break; case XmINDETERMINATE: *state = XmUNSET; break; } } /**************************************************************************** * * Arm * This function processes button down occuring on the togglebutton. * Mark the togglebutton as armed and display it armed. * The callbacks for XmNarmCallback are called. * ***************************************************************************/ /* ARGSUSED */ static void Arm( Widget wid, XEvent *event, String *params, Cardinal *num_params ) { XmToggleButtonWidget tb = (XmToggleButtonWidget) wid ; (void)XmProcessTraversal( (Widget) tb, XmTRAVERSE_CURRENT); if (tb->toggle.toggle_mode == XmTOGGLE_INDETERMINATE) NextState(&tb->toggle.visual_set); else IsOn(tb) = (tb->toggle.set == XmSET)? XmUNSET : XmSET; tb->toggle.Armed = TRUE; if (tb->toggle.ind_on) DrawToggle(tb); else { if (tb->primitive.shadow_thickness > 0) DrawToggleShadow (tb); if (tb->toggle.fill_on_select && !Lab_IsPixmap(tb)) DrawToggleLabel(tb); } if (Lab_IsPixmap(tb)) SetAndDisplayPixmap(tb, event, NULL); if (tb->toggle.arm_CB) { XFlush(XtDisplay(tb)); ToggleButtonCallback(tb, XmCR_ARM, tb->toggle.set, event); } } /************************************************************************ * * Select * Mark the togglebutton as unarmed (i.e. inactive). * If the button release occurs inside of the ToggleButton, the * callbacks for XmNvalueChangedCallback are called. * ************************************************************************/ /* ARGSUSED */ static void Select( Widget wid, XEvent *event, String *params, Cardinal *num_params ) { XmToggleButtonWidget tb = (XmToggleButtonWidget) wid ; static XmToggleButtonWidget prev = NULL; XmToggleButtonCallbackStruct call_value; Boolean hit; XmMenuSystemTrait menuSTrait; if (tb->toggle.Armed == FALSE) return; tb->toggle.Armed = FALSE; if ((prev == tb) && ((tb->toggle.ind_type == XmONE_OF_MANY_ROUND)|| (tb->toggle.ind_type == XmONE_OF_MANY_DIAMOND)|| (tb->toggle.ind_type == XmONE_OF_MANY))) return; /* CR 8068: Verify that this is in fact a button event. */ /* CR 9181: Consider clipping when testing visibility. */ /* Check to see if BtnUp is inside the widget */ hit = ((event->xany.type == ButtonPress || event->xany.type == ButtonRelease) && _XmGetPointVisibility(wid, event->xbutton.x_root, event->xbutton.y_root)); if (hit) { if (tb->toggle.toggle_mode == XmTOGGLE_INDETERMINATE) NextState(&tb->toggle.set); else tb->toggle.set = !tb->toggle.set; } /* CR 7803: Suppress redundant redraws. */ if (tb->toggle.set != tb->toggle.visual_set) { /* Redisplay after changing state. */ XtExposeProc expose; _XmProcessLock(); expose = ((WidgetClass)XtClass(tb))->core_class.expose; _XmProcessUnlock(); (* (expose)) (wid, event, NULL); } if (hit) { /* UNDOING this fix .... */ /* CR 8904: Notify value_changed before entry so that state is */ /* reported correctly even if the entry callback resets it. */ menuSTrait = (XmMenuSystemTrait) XmeTraitGet((XtPointer) XtClass(XtParent(tb)), XmQTmenuSystem); if (menuSTrait != NULL) { call_value.reason = XmCR_VALUE_CHANGED; call_value.event = event; call_value.set = tb->toggle.set; menuSTrait->entryCallback(XtParent(tb), (Widget) tb, &call_value); } if ((! tb->label.skipCallback) && (tb->toggle.value_changed_CB)) { XFlush(XtDisplay(tb)); ToggleButtonCallback(tb, XmCR_VALUE_CHANGED, tb->toggle.set, event); } } prev = tb; } /********************************************************************** * * Disarm * The callbacks for XmNdisarmCallback are called.. * ************************************************************************/ /* ARGSUSED */ static void Disarm( Widget wid, XEvent *event, String *params, Cardinal *num_params ) { XmToggleButtonWidget tb = (XmToggleButtonWidget) wid ; if (tb->toggle.disarm_CB) ToggleButtonCallback(tb, XmCR_DISARM, tb->toggle.set, event); /* BEGIN OSF Fix pir 2826 */ /* CR 7803: Suppress redundant redraws. */ if (tb->toggle.set != tb->toggle.visual_set) Redisplay((Widget) tb, event, (Region) NULL); /* END OSF Fix pir 2826 */ } static void TB_FixTearoff( XmToggleButtonWidget tb) { if (XmMENU_PULLDOWN == tb->label.menu_type) { Widget mwid = XmGetPostedFromWidget(XtParent(tb)); if (mwid && XmIsRowColumn(mwid) && (XmMENU_OPTION == RC_Type(mwid)) && _XmIsActiveTearOff(XtParent(tb))) XmProcessTraversal((Widget) tb, XmTRAVERSE_CURRENT); } } /************************************************************************ * * ArmAndActivate * This routine arms and activates a ToggleButton. It is called on * Return and a Space, as well as when a mnemonic or * button accelerator has been activated. * ************************************************************************/ /* ARGSUSED */ static void ArmAndActivate( Widget wid, XEvent *event, String *params, Cardinal *num_params ) { XmToggleButtonWidget tb = (XmToggleButtonWidget) wid ; XmToggleButtonCallbackStruct call_value; Boolean already_armed = tb->toggle.Armed; Boolean is_menupane = Lab_IsMenupane(tb); Boolean torn_has_focus = FALSE; XmMenuSystemTrait menuSTrait; menuSTrait = (XmMenuSystemTrait) XmeTraitGet((XtPointer) XtClass(XtParent(tb)), XmQTmenuSystem); if (is_menupane && !XmIsMenuShell(XtParent(XtParent(tb)))) { if (XmeFocusIsInShell((Widget)tb)) { /* In case allowAcceleratedInsensitiveUnmanagedMenuItems is True */ if (!XtIsSensitive((Widget)tb) || (!XtIsManaged((Widget)tb))) return; torn_has_focus = TRUE; } } tb->toggle.Armed = FALSE; if (tb->toggle.toggle_mode == XmTOGGLE_INDETERMINATE) { NextState(&tb->toggle.visual_set); NextState(&tb->toggle.set); } else { tb->toggle.set = (tb->toggle.set == XmSET)? XmUNSET : XmSET; IsOn(tb) = tb->toggle.set; } if (is_menupane && menuSTrait != NULL) { /* CR 7799: Torn off menus shouldn't be shared, so don't reparent. */ if (torn_has_focus) menuSTrait->popdown(XtParent(tb), event); else menuSTrait->buttonPopdown(XtParent(tb), event); if (torn_has_focus) XmProcessTraversal((Widget) tb, XmTRAVERSE_CURRENT); /* Draw the toggle indicator in case of tear off */ if (tb->toggle.ind_on) DrawToggle(tb); else if (tb->toggle.fill_on_select && !Lab_IsPixmap(tb)) DrawToggleLabel(tb); if (Lab_IsPixmap(tb)) SetAndDisplayPixmap( tb, event, NULL); } else { if (tb->toggle.ind_on) DrawToggle(tb); else { if (tb->primitive.shadow_thickness > 0) DrawToggleShadow (tb); if (tb->toggle.fill_on_select && !Lab_IsPixmap(tb)) DrawToggleLabel (tb); } if (Lab_IsPixmap(tb)) SetAndDisplayPixmap( tb, event, NULL); } /* If the parent is menu system able, set the lastSelectToplevel before * the arm. It's ok if this is recalled later. */ if (menuSTrait != NULL) menuSTrait->getLastSelectToplevel(XtParent(tb)); if (tb->toggle.arm_CB && !already_armed) { XFlush(XtDisplay(tb)); ToggleButtonCallback(tb, XmCR_ARM, tb->toggle.set, event); } /* UNDOING this fix .... */ /* CR 8904: Notify value_changed before entry so that state is */ /* reported correctly even if the entry callback resets it. */ /* if the parent is menu system able, notify it about the select */ if (menuSTrait != NULL) { call_value.reason = XmCR_VALUE_CHANGED; call_value.event = event; call_value.set = tb->toggle.set; menuSTrait->entryCallback(XtParent(tb), (Widget) tb, &call_value); } if ((! tb->label.skipCallback) && (tb->toggle.value_changed_CB)) { XFlush(XtDisplay(tb)); ToggleButtonCallback(tb, XmCR_VALUE_CHANGED, tb->toggle.set, event); } if (tb->toggle.disarm_CB) { XFlush(XtDisplay(tb)); ToggleButtonCallback(tb, XmCR_DISARM, tb->toggle.set, event); } if (is_menupane) { if (torn_has_focus && XtIsSensitive(wid)) { tb->toggle.Armed = TRUE; if (tb->toggle.arm_CB) { XFlush(XtDisplay(tb)); ToggleButtonCallback(tb, XmCR_ARM, tb->toggle.set, event); } } else if (menuSTrait != NULL) { menuSTrait->reparentToTearOffShell(XtParent(tb), event); TB_FixTearoff(tb); } } } /************************************************************************ * * BtnDown * This function processes a button down occuring on the togglebutton * when it is in a popup, pulldown, or option menu. * Popdown the posted menu. * Turn parent's traversal off. * Mark the togglebutton as armed (i.e. active). * The callbacks for XmNarmCallback are called. * ************************************************************************/ /* ARGSUSED */ static void BtnDown( Widget wid, XEvent *event, String *params, Cardinal *num_params ) { XmToggleButtonWidget tb = (XmToggleButtonWidget) wid ; Boolean validButton = False; Boolean already_armed; ShellWidget popup; XmMenuSystemTrait menuSTrait; menuSTrait = (XmMenuSystemTrait) XmeTraitGet((XtPointer) XtClass(XtParent(tb)), XmQTmenuSystem); if (menuSTrait == NULL) return; /* Support menu replay, free server input queue until next button event */ XAllowEvents(XtDisplay(tb), SyncPointer, CurrentTime); already_armed = tb->toggle.Armed; tb->toggle.Armed = TRUE; if (event && (event->type == ButtonPress)) { XmDisplay dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(wid)); Boolean etched_in = dpy->display.enable_etched_in_menu; if ((etched_in) && ((tb->toggle.ind_on) || (!(tb->toggle.ind_on) && !(tb->toggle.fill_on_select)))) { DrawEtchedInMenu(tb); if (tb->toggle.ind_on) DrawToggle(tb); } validButton = menuSTrait->verifyButton(XtParent(tb), event); } if (!validButton) return; _XmSetInDragMode((Widget)tb, True); /* Popdown other popups that may be up */ if (!(popup = (ShellWidget)_XmGetRC_PopupPosted(XtParent(tb)))) { if (!XmIsMenuShell(XtParent(XtParent(tb)))) { /* In case tear off not armed and no grabs in place, do it now. * Ok if already armed and grabbed - nothing done. */ menuSTrait->tearOffArm(XtParent(tb)); } } if (popup) { /* Widget w; */ if (popup->shell.popped_up) menuSTrait->popdownEveryone((Widget) popup, event); /* If the active_child is a cascade (highlighted), then unhighlight it.*/ /* * w = ((XmManagerWidget)XtParent(tb))->manager.active_child; * if (w && (XmIsCascadeButton(w) || XmIsCascadeButtonGadget(w))) * XmCascadeButtonHighlight (w, FALSE); */ } /* Set focus to this button. This must follow the possible * unhighlighting of the CascadeButton else it'll screw up active_child. */ (void)XmProcessTraversal( (Widget) tb, XmTRAVERSE_CURRENT); /* get the location cursor - get consistent with Gadgets */ if (tb->toggle.arm_CB && !already_armed) { XFlush (XtDisplay (tb)); ToggleButtonCallback(tb, XmCR_ARM, tb->toggle.set, event); } _XmRecordEvent(event); } /************************************************************************ * * BtnUp * This function processes a button up occuring on the togglebutton * when it is in a popup, pulldown, or option menu. * Mark the togglebutton as unarmed (i.e. inactive). * The callbacks for XmNvalueChangedCallback are called. * The callbacks for XmNdisarmCallback are called. * ************************************************************************/ /* ARGSUSED */ static void BtnUp( Widget wid, XEvent *event, String *params, Cardinal *num_params ) { XmToggleButtonWidget tb = (XmToggleButtonWidget) wid ; XmToggleButtonCallbackStruct call_value; Boolean validButton = False; Boolean popped_up; Boolean is_menupane = Lab_IsMenupane(tb); Widget shell = XtParent(XtParent(tb)); XmMenuSystemTrait menuSTrait; menuSTrait = (XmMenuSystemTrait) XmeTraitGet((XtPointer) XtClass(XtParent(tb)), XmQTmenuSystem); if (menuSTrait == NULL) return; if (event && (event->type == ButtonRelease)) validButton = menuSTrait->verifyButton(XtParent(tb), event); if (!validButton || (tb->toggle.Armed == FALSE)) return; tb->toggle.Armed = FALSE; if (is_menupane && !XmIsMenuShell(shell)) popped_up = menuSTrait->popdown((Widget) tb, event); else popped_up = menuSTrait->buttonPopdown((Widget) tb, event); _XmRecordEvent(event); if (popped_up) return; /* Check to see if BtnUp is inside the widget */ /* CR 9181: Consider clipping when testing visibility. */ if ((event->xany.type == ButtonPress || event->xany.type == ButtonRelease) && _XmGetPointVisibility(wid, event->xbutton.x_root, event->xbutton.y_root)) { if (tb->toggle.toggle_mode == XmTOGGLE_INDETERMINATE) { NextState(&tb->toggle.visual_set); NextState(&tb->toggle.set); } else { tb->toggle.set = (tb->toggle.set == XmSET)? XmUNSET : XmSET; IsOn(tb) = tb->toggle.set; } /* UNDOING this fix ... */ /* CR 8904: Notify value_changed before entry so that state is */ /* reported correctly even if the entry callback resets it. */ /* if the parent is menu system able, notify it about the select */ if (menuSTrait != NULL) { call_value.reason = XmCR_VALUE_CHANGED; call_value.event = event; call_value.set = tb->toggle.set; menuSTrait->entryCallback(XtParent(tb), (Widget) tb, &call_value); } if ((! tb->label.skipCallback) && (tb->toggle.value_changed_CB)) { XFlush(XtDisplay(tb)); ToggleButtonCallback(tb, XmCR_VALUE_CHANGED, tb->toggle.set, event); } if (tb->toggle.disarm_CB) ToggleButtonCallback(tb, XmCR_DISARM, tb->toggle.set, event); if (is_menupane) { if (!XmIsMenuShell(shell)) { if (XtIsSensitive((Widget)tb)) { tb->toggle.Armed = TRUE; if (tb->toggle.ind_on) DrawToggle(tb); else if (tb->toggle.fill_on_select && !Lab_IsPixmap(tb)) DrawToggleLabel(tb); if (Lab_IsPixmap(tb)) SetAndDisplayPixmap( tb, event, NULL); if (tb->toggle.arm_CB) { XFlush(XtDisplay(tb)); ToggleButtonCallback(tb, XmCR_ARM, tb->toggle.set, event); } } } else menuSTrait->reparentToTearOffShell(XtParent(tb), event); } } _XmSetInDragMode((Widget)tb, False); /* For the benefit of tear off menus, we must set the focus item * to this button. In normal menus, this would not be a problem * because the focus is cleared when the menu is unposted. */ if (!XmIsMenuShell(shell)) XmProcessTraversal((Widget) tb, XmTRAVERSE_CURRENT); TB_FixTearoff(tb); } /************************************************************************ * * GetUnselectGC * Get the graphics context to be used to fill the interior of * a square or diamond when unselected. * ************************************************************************/ static void GetUnselectGC( XmToggleButtonWidget tw ) { XGCValues values; XtGCMask valueMask; valueMask = GCForeground | GCBackground | GCFillStyle | GCGraphicsExposures; values.foreground = tw->toggle.unselect_color; values.background = tw->core.background_pixel; values.fill_style = FillSolid; values.graphics_exposures = FALSE; tw->toggle.unselect_GC = XtGetGC((Widget) tw, valueMask, &values); } /************************************************************************ * * GetGC * Get the graphics context to be used to fill the interior of * a square or diamond when selected, and the arm GC used in a * menu if enableEtchedInMenu is True. * ************************************************************************/ static void GetGC( XmToggleButtonWidget tw ) { XGCValues values; XtGCMask valueMask; XFontStruct *fs = (XFontStruct *) NULL; Pixel sel_color, select_pixel; XmDisplay dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(tw)); Boolean etched_in = dpy->display.enable_etched_in_menu; /* Differentiate background and select colors on monochrome displays or ** others on which we have indistinguishable colors. */ if ((DefaultDepthOfScreen(XtScreen(tw)) == 1) || (tw->core.background_pixel == tw->toggle.select_color)) sel_color = tw->primitive.foreground; else sel_color = tw->toggle.select_color; valueMask = 0; valueMask |= GCForeground, values.foreground = sel_color; valueMask |= GCBackground, values.background = tw->core.background_pixel; valueMask |= GCFillStyle, values.fill_style = FillSolid; valueMask |= GCGraphicsExposures, values.graphics_exposures = FALSE; tw->toggle.select_GC = XtAllocateGC((Widget)tw, 0, valueMask, &values, 0, 0); /* When foreground and select colors coincide, this GC is used * by XmLabel to draw the text. It requires a font to pacify * the XmString draw functions. */ valueMask = 0; if (XmeRenderTableGetDefaultFont(tw->label.font, &fs)) valueMask |= GCFont, values.font = fs->fid; valueMask |= GCForeground, values.foreground = tw->core.background_pixel; valueMask |= GCBackground, values.background = tw->primitive.foreground; valueMask |= GCFillStyle, values.fill_style = FillSolid; valueMask |= GCGraphicsExposures, values.graphics_exposures = FALSE; valueMask |= GCLineWidth, values.line_width = 1; tw->toggle.background_gc = XtGetGC((Widget) tw, valueMask, &values); valueMask = 0; valueMask |= GCFillStyle, values.fill_style = FillOpaqueStippled; valueMask |= GCGraphicsExposures, values.graphics_exposures = FALSE; valueMask |= GCStipple, values.stipple = XmGetPixmapByDepth(XtScreen((Widget)(tw)), XmS50_foreground, 1, 0, 1); valueMask |= GCLineWidth, values.line_width = 1; tw->toggle.indeterminate_GC = XtAllocateGC((Widget)tw, 0, valueMask, &values, GCForeground | GCBackground, 0); /* The valueMask and values are inherited from above. */ valueMask &= ~GCLineWidth; valueMask |= GCForeground, values.foreground = tw->core.background_pixel; valueMask |= GCBackground, values.background = tw->primitive.foreground; tw->toggle.indeterminate_box_GC = XtGetGC((Widget) tw, valueMask, &values); /* Create the ArmGC for filling in background if we are in a menu and enableEtchedInMenu is True. */ if ((Lab_IsMenupane(tw)) && etched_in) { XmGetColors(XtScreen(tw), tw->core.colormap, tw->core.background_pixel, NULL, NULL, NULL, &select_pixel); valueMask = 0; valueMask |= GCForeground, values.foreground = select_pixel; valueMask |= GCBackground, values.background = tw->primitive.foreground; if (fs != NULL) valueMask |= GCFont, values.font = fs->fid; valueMask |= GCGraphicsExposures, values.graphics_exposures = FALSE; tw->toggle.arm_GC = XtGetGC((Widget) tw, valueMask, &values); } } /*************************************<->************************************* * * Initialize * *************************************<->***********************************/ /*ARGSUSED*/ static void Initialize( Widget rw, Widget nw, ArgList args, Cardinal *num_args ) { XmToggleButtonWidget request = (XmToggleButtonWidget) rw ; XmToggleButtonWidget new_w = (XmToggleButtonWidget) nw ; XtWidgetProc resize; new_w->toggle.Armed = FALSE; /* if menuProcs is not set up yet, try again */ _XmProcessLock(); resize = xmLabelClassRec.core_class.resize; if (xmLabelClassRec.label_class.menuProcs == (XmMenuProc)NULL) xmLabelClassRec.label_class.menuProcs = (XmMenuProc)_XmGetMenuProcContext(); _XmProcessUnlock(); if (Lab_IsMenupane(new_w)) { /* If the shadow thickness hasn't been set yet, inherit it from the menu parent, instead of a hard-coded 2, as before. The only draw back is that is the parent has also 0, then the toggle shadow is 0, which is not very good in a menu, but at least consistent with the other buttons */ if (new_w->primitive.shadow_thickness <= 0) { Dimension parent_st ; XtVaGetValues(XtParent(nw), XmNshadowThickness, &parent_st, NULL); new_w->primitive.shadow_thickness = parent_st; } if (new_w->toggle.visible == XmINVALID_BOOLEAN) new_w->toggle.visible = FALSE; new_w->primitive.traversal_on = TRUE; } else if (new_w->toggle.visible == XmINVALID_BOOLEAN) new_w->toggle.visible = TRUE; /* * If the indicatorType has not been set, then * find out if radio behavior is set for RowColumn parents and * then set indicatorType. If radio behavior is true, default to * one of many, else default to n of many. */ if ((new_w->toggle.ind_type == XmINVALID_TYPE) || !XmRepTypeValidValue (XmRID_INDICATOR_TYPE, new_w->toggle.ind_type, (Widget) new_w)) { Boolean radio = FALSE; if (XmIsRowColumn(XtParent(new_w))) { XtVaGetValues(XtParent(new_w), XmNradioBehavior, &radio, NULL); } if (radio) new_w->toggle.ind_type = XmONE_OF_MANY; else new_w->toggle.ind_type = XmN_OF_MANY; } /* * This resource defaults to true if an indicator box is drawn. */ if (new_w->toggle.fill_on_select == XmINVALID_BOOLEAN) { if (DRAWBOX(NormalizeIndOn(new_w))) new_w->toggle.fill_on_select = True; else if (IsOneOfMany(new_w->toggle.ind_type) && new_w->toggle.ind_on) new_w->toggle.fill_on_select = True; else new_w->toggle.fill_on_select = False; } /* Tristate buttons ain't allowed in one-of-many land. */ if (IsOneOfMany(new_w->toggle.ind_type)) new_w->toggle.toggle_mode = XmTOGGLE_BOOLEAN; /* If necessary use the On pixmaps in place of the Indeterminate ones. */ if (IsNull(PixmapInd(new_w)) && !IsNull(PixmapOn(new_w))) PixmapInd(new_w) = PixmapOn(new_w); if (IsNull(PixmapInsenInd(new_w)) && !IsNull(PixmapInsenOn(new_w))) PixmapInsenInd(new_w) = PixmapInsenOn(new_w); /* If necessary use PixmapOn in place of PixmapOff. */ if (IsNull(PixmapOff(new_w)) && !IsNull(PixmapOn(new_w))) { PixmapOff(new_w) = PixmapOn(new_w); if (request->core.width == 0) new_w->core.width = 0; if (request->core.height == 0) new_w->core.height = 0; _XmCalcLabelDimensions((Widget) new_w); (* resize)( (Widget) new_w); } /* If necessary use PixmapInsenOn in place of PixmapInsenOff. */ if (IsNull(PixmapInsenOff(new_w)) && !IsNull(PixmapInsenOn(new_w))) { PixmapInsenOff(new_w) = PixmapInsenOn(new_w); if (request->core.width == 0) new_w->core.width = 0; if (request->core.height == 0) new_w->core.height = 0; _XmCalcLabelDimensions((Widget) new_w); (* resize)( (Widget) new_w); } /* BEGIN OSF Fix pir 1778 */ if (Lab_IsPixmap(new_w) && (!IsNull(PixmapOff(new_w)) || !IsNull(PixmapInsenOff(new_w)) || !IsNull(PixmapOn(new_w)) || !IsNull(PixmapInsenOn(new_w)) || !IsNull(PixmapInd(new_w)) || !IsNull(PixmapInsenInd(new_w)))) { if (request->core.width == 0) new_w->core.width = 0; if (request->core.height == 0) new_w->core.height = 0; SetToggleSize(new_w); } /* END OSF Fix pir 1778 */ if (new_w->toggle.indicator_dim == XmINVALID_DIMENSION) { if (new_w->toggle.ind_on) { /* Determine how high the toggle indicator should be. */ if Lab_IsPixmap(new_w) { /* Set indicator size proportional to size of pixmap. */ if ( !IsNull(PixmapOn(new_w)) || !IsNull(PixmapInsenOn(new_w)) || !IsNull(PixmapOff(new_w)) || !IsNull(PixmapInsenOff(new_w)) || !IsNull(PixmapInd(new_w)) || !IsNull(PixmapInsenInd(new_w))) if (new_w->label.TextRect.height < 13) new_w->toggle.indicator_dim = new_w->label.TextRect.height; else new_w->toggle.indicator_dim = 13 + (new_w->label.TextRect.height/13); else new_w->toggle.indicator_dim = XmDEFAULT_INDICATOR_DIM; } else { /* Set indicator size proportional to size of font. */ Dimension height; int line_count; height = XmStringHeight (new_w->label.font, new_w->label._label); if ((line_count = XmStringLineCount (new_w->label._label)) < 1) line_count = 1; /* Shiz recommends toggles in menus have smaller indicators */ if (Lab_IsMenupane(new_w)) new_w->toggle.indicator_dim = MAX(XmDEFAULT_INDICATOR_DIM, (height / ((Dimension)line_count))*2/3); else new_w->toggle.indicator_dim = MAX(XmDEFAULT_INDICATOR_DIM, height / ((Dimension)line_count)); } } else { new_w->toggle.indicator_dim = 0; } new_w->toggle.indicator_set = FALSE; } else { new_w->toggle.indicator_set = TRUE; } /* CR 2337: Maintain original margin values. */ new_w->toggle.ind_left_delta = 0; new_w->toggle.ind_right_delta = 0; new_w->toggle.ind_top_delta = 0; new_w->toggle.ind_bottom_delta = 0; if (new_w->toggle.ind_on) { /* * Enlarge the text rectangle if needed to accomodate the size of * indicator button. Adjust the dimensions of superclass Label-Gadget * so that the toggle-button may be accommodated in it. */ int maxIndicatorSize; int delta; int boxSize; /* BEGIN OSF Fix pir 2480 */ if (! Lab_IsMenupane(new_w)) maxIndicatorSize = new_w->toggle.indicator_dim + 2*Xm3D_ENHANCE_PIXEL; else maxIndicatorSize = new_w->toggle.indicator_dim; /* END OSF Fix pir 2480 */ boxSize = ((int) new_w->label.TextRect.height + (int) new_w->label.margin_top + (int) new_w->label.margin_bottom); if (maxIndicatorSize > boxSize) { delta = (maxIndicatorSize - boxSize) / 2; new_w->toggle.ind_top_delta = delta; new_w->label.margin_top += new_w->toggle.ind_top_delta; new_w->toggle.ind_bottom_delta = delta; new_w->label.margin_bottom += new_w->toggle.ind_bottom_delta; } /* CR 2337: Make room for toggle indicator and spacing */ if (LayoutIsRtoLP(new_w)) { delta = (new_w->toggle.indicator_dim + new_w->toggle.spacing - new_w->label.margin_right); if (delta > 0) { new_w->toggle.ind_right_delta = delta; new_w->label.margin_right += delta; } } else { delta = (new_w->toggle.indicator_dim + new_w->toggle.spacing - new_w->label.margin_left); if (delta > 0) { new_w->toggle.ind_left_delta = delta; new_w->label.margin_left += delta; } } } if (request->core.width == 0) { new_w->core.width = new_w->label.TextRect.width + 2 * new_w->label.margin_width + new_w->label.margin_right + new_w->label.margin_left + 2 * (new_w->primitive.highlight_thickness + new_w->primitive.shadow_thickness); if (new_w->core.width == 0) new_w->core.width = 1; if ((new_w->label._acc_text != NULL) && (new_w->toggle.ind_on)) if (LayoutIsRtoLP(new_w)) new_w->label.acc_TextRect.x = new_w->primitive.highlight_thickness + new_w->primitive.shadow_thickness + new_w->label.margin_width; else new_w->label.acc_TextRect.x = new_w->core.width - new_w->primitive.highlight_thickness - new_w->primitive.shadow_thickness - new_w->label.margin_width - new_w->label.margin_right + LABEL_ACC_PAD; } if (request->core.height == 0) new_w->core.height = MAX(new_w->toggle.indicator_dim, new_w->label.TextRect.height + 2 * new_w->label.margin_height + new_w->label.margin_top + new_w->label.margin_bottom) + 2 * (new_w->primitive.highlight_thickness + new_w->primitive.shadow_thickness); new_w->label.TextRect.y = (short) new_w->primitive.highlight_thickness + new_w->primitive.shadow_thickness + new_w->label.margin_height + new_w->label.margin_top + ((new_w->core.height - new_w->label.margin_top - new_w->label.margin_bottom - (2 * (new_w->label.margin_height + new_w->primitive.highlight_thickness + new_w->primitive.shadow_thickness)) - new_w->label.TextRect.height) / 2); if (new_w->core.height == 0) new_w->core.height = 1; new_w->toggle.visual_set = new_w->toggle.set; /* Display as set if XmNset is TRUE when the toggle first comes up. */ if (XmSET == new_w->toggle.set) IsOn(new_w) = XmSET; else IsOn(new_w) = XmUNSET; { XtWidgetProc resize; _XmProcessLock(); resize = new_w->core.widget_class->core_class.resize; _XmProcessUnlock(); (* (resize)) ((Widget) new_w); } /* unselect same as background unless set. */ if (new_w->toggle.unselect_color == XmINVALID_PIXEL) new_w->toggle.unselect_color = new_w->core.background_pixel; /* Deal with selectColor */ new_w->toggle.reversed_select = (new_w->toggle.select_color == XmREVERSED_GROUND_COLORS); if (new_w->toggle.select_color == XmDEFAULT_SELECT_COLOR) { /* CR 9923: Copy all bytes of the resulting pixel. */ XrmValue value; _XmSelectColorDefault((Widget)new_w, XtOffsetOf(XmToggleButtonRec, toggle.select_color), &value); assert(value.size == sizeof(Pixel)); new_w->toggle.select_color = *((Pixel*) value.addr); } else if (new_w->toggle.select_color == XmREVERSED_GROUND_COLORS) { new_w->toggle.select_color = new_w->primitive.foreground; } else if (new_w->toggle.select_color == XmHIGHLIGHT_COLOR) { new_w->toggle.select_color = new_w->primitive.highlight_color; } GetGC (new_w); GetUnselectGC(new_w); } /************************************************************************ * * Destroy * Free toggleButton's graphic context. * ************************************************************************/ static void Destroy( Widget wid ) { XmToggleButtonWidget tw = (XmToggleButtonWidget) wid ; XmDisplay dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(wid)); Boolean etched_in = dpy->display.enable_etched_in_menu; XtReleaseGC ((Widget) tw, tw->toggle.select_GC); XtReleaseGC ((Widget) tw, tw->toggle.background_gc); XtReleaseGC ((Widget) tw, tw->toggle.unselect_GC); XtReleaseGC ((Widget) tw, tw->toggle.indeterminate_GC); XtReleaseGC ((Widget) tw, tw->toggle.indeterminate_box_GC); if (Lab_IsMenupane(tw) && etched_in) XtReleaseGC ((Widget) tw, tw->toggle.arm_GC); } static void DrawBox(XmToggleButtonWidget w, GC top_gc, GC bot_gc, GC fillgc, int x, int y, int edge, Dimension margin) { int shadow = w->toggle.detail_shadow_thickness; XmeDrawShadows(XtDisplay ((Widget) w), XtWindow ((Widget) w), top_gc, bot_gc, x, y, edge, edge, shadow, XmSHADOW_OUT); /* Don't fill the background on mono screens if we're going to */ /* draw a glyph */ if ((DefaultDepthOfScreen(XtScreen(w)) == 1) && DRAWGLYPH(NormalizeIndOn(w))) return; shadow += margin; if (edge > (shadow * 2)) XFillRectangle (XtDisplay ((Widget) w), XtWindow ((Widget) w), fillgc, x + shadow, y + shadow, edge - (shadow * 2), edge - (shadow * 2)); } /*************************************<->************************************* * * DrawToggle(w) * Depending on the state of this widget, draw the Toggle. * That is draw the True/False indicator next to the label. * *************************************<->***********************************/ static void DrawToggle (XmToggleButtonWidget w ) { int x, y, edge; Dimension margin; XGCValues values; Display *dpy = XtDisplay((Widget) w); Drawable drawable = XtWindow((Widget) w); XmDisplay dpyxm = (XmDisplay) XmGetXmDisplay(XtDisplay(w)); Boolean etched_in = dpyxm->display.enable_etched_in_menu; /* Get size of indicator i.e. bounding box */ if (Lab_IsPixmap(w) || XmStringEmpty(w->label._label)) edge = w->toggle.indicator_dim; else edge = MIN((int)w->toggle.indicator_dim, MAX(0, ((int)w->core.height - 2*(w->primitive.highlight_thickness + w->primitive.shadow_thickness + (int)w->label.margin_height) + w->label.margin_top + w->label.margin_bottom))); /* Touch up the appearance of filled background. */ if ((DefaultDepthOfScreen(XtScreen(w)) > 1) && (w->primitive.top_shadow_color != w->toggle.select_color) && (w->primitive.bottom_shadow_color != w->toggle.select_color)) margin = 0; else margin = 1; if (LayoutIsRtoLP(w)) x = (int)w->core.width - w->primitive.highlight_thickness - w->primitive.shadow_thickness - w->label.margin_width - w->toggle.indicator_dim; else x = w->primitive.highlight_thickness + w->primitive.shadow_thickness + w->label.margin_width; if (Lab_IsPixmap(w) || XmStringEmpty(w->label._label)) y = (int)((w->core.height - w->toggle.indicator_dim))/2; else { int fudge = Xm3D_ENHANCE_PIXEL; y = w->label.TextRect.y; if (Lab_IsMenupane(w)) y += (w->toggle.indicator_dim + 2) / 4; /* adjust in menu */ /* CR 2337: Keep large indicators inside the toggle. */ /* Is this definition of fudge right??? */ if (w->toggle.ind_top_delta > fudge) y -= (w->toggle.ind_top_delta - fudge); } if (w->toggle.visible || (w->toggle.visual_set != XmUNSET)) { /* The toggle indicator should be visible. */ GC top_gc, bot_gc, fill_gc, glyph_gc; unsigned char normal_ind_on = NormalizeIndOn(w); switch (w->toggle.visual_set) { case XmUNSET: top_gc = w->primitive.top_shadow_GC; bot_gc = w->primitive.bottom_shadow_GC; /* use the arm GC in a menu if armed and enableEtchedInMenu is set */ if (Lab_IsMenupane(w) && etched_in && w->toggle.Armed) fill_gc = (w->toggle.fill_on_select ? w->toggle.unselect_GC : w->toggle.arm_GC); else fill_gc = (w->toggle.fill_on_select ? w->toggle.unselect_GC : w->toggle.background_gc); glyph_gc = None; break; case XmSET: top_gc = w->primitive.bottom_shadow_GC; bot_gc = w->primitive.top_shadow_GC; /* use the arm GC in a menu if armed and enableEtchedInMenu is set */ if (Lab_IsMenupane(w) && etched_in && w->toggle.Armed) fill_gc = (w->toggle.fill_on_select ? w->toggle.select_GC : w->toggle.arm_GC); else fill_gc = (w->toggle.fill_on_select ? w->toggle.select_GC : w->toggle.background_gc); glyph_gc = ((w->toggle.reversed_select && DRAWBOX(normal_ind_on)) ? w->toggle.background_gc : w->label.normal_GC); /* CR 9791: Label's normal_gc has a dynamic clip_mask. */ if (glyph_gc == w->label.normal_GC) XSetClipMask(dpy, glyph_gc, None); break; case XmINDETERMINATE: top_gc = bot_gc = w->toggle.indeterminate_box_GC; /* use the arm GC in a menu if armed and enableEtchedInMenu is set */ if (Lab_IsMenupane(w) && etched_in && w->toggle.Armed) fill_gc = (w->toggle.fill_on_select ? w->toggle.indeterminate_GC : w->toggle.arm_GC); else fill_gc = (w->toggle.fill_on_select ? w->toggle.indeterminate_GC : w->toggle.background_gc); glyph_gc = w->toggle.indeterminate_GC; break; default: assert(False); return; } switch (NormalizeIndType(w)) { case XmN_OF_MANY: { /* If the toggle indicator is square shaped then adjust the * indicator width and height, so that it looks proportional * to a diamond shaped indicator of the same width and height */ int new_edge; Dimension box_margin = (DRAWBOX(normal_ind_on) ? w->toggle.detail_shadow_thickness : 0); /* Subtract 3 pixels + 10% from the width and height. */ new_edge = edge - 3 - ((edge - 10)/10); /* Adjust x,y to center the indicator relative to the label */ y = y + ((edge - new_edge) / 2); x = x + ((edge - new_edge) / 2); edge = new_edge; switch(w->toggle.visual_set) { case XmUNSET: if (DRAW3DBOX(normal_ind_on)) DrawBox(w, top_gc, bot_gc, fill_gc, x, y, edge, margin); else if (DRAWFLATBOX(normal_ind_on)) DrawBox(w, bot_gc, bot_gc, fill_gc, x, y, edge, margin); else if (edge > 0) XFillRectangle(dpy, drawable, fill_gc, x, y, edge, edge); break; case XmSET: if (DRAW3DBOX(normal_ind_on)) DrawBox(w, top_gc, bot_gc, fill_gc, x, y, edge, margin); else if (DRAWFLATBOX(normal_ind_on)) DrawBox(w, top_gc, top_gc, fill_gc, x, y, edge, margin); else if (edge > 0) XFillRectangle(dpy, drawable, fill_gc, x, y, edge, edge); if (!DRAWBOX(normal_ind_on) || ((edge - 2 * box_margin) >= MIN_GLYPH_SIZE)) { if (DRAWCHECK(normal_ind_on)) XmeDrawIndicator(dpy, drawable, glyph_gc, x, y, edge, edge, box_margin, normal_ind_on); else if (DRAWCROSS(normal_ind_on)) XmeDrawIndicator(dpy, drawable, glyph_gc, x, y, edge, edge, box_margin, normal_ind_on); } break; case XmINDETERMINATE: if (w->toggle.fill_on_select) { /* Fetch the select_color GetGC() actually used. */ XGetGCValues(dpy, w->toggle.select_GC, GCForeground, &values); values.background = values.foreground; values.foreground = w->toggle.unselect_color; XChangeGC(dpy, fill_gc, GCForeground|GCBackground, &values); } else if (DRAWBOX(normal_ind_on)) { /* This GC should have the right values already. */ fill_gc = w->toggle.indeterminate_box_GC; } if (DRAWBOX(normal_ind_on)) DrawBox(w, bot_gc, bot_gc, fill_gc, x, y, edge, margin); else if (edge > 0) XFillRectangle(dpy, drawable, fill_gc, x, y, edge, edge); if (w->toggle.reversed_select) { values.foreground = w->core.background_pixel; values.background = w->primitive.foreground; } else { values.foreground = w->primitive.foreground; values.background = w->core.background_pixel; } if (!DRAWBOX(normal_ind_on) || ((edge - 2 * box_margin) >= MIN_GLYPH_SIZE)) { if (DRAWCHECK(normal_ind_on)) { XChangeGC(dpy, glyph_gc, GCForeground|GCBackground, &values); XmeDrawIndicator(dpy, drawable, glyph_gc, x, y, edge, edge, box_margin, normal_ind_on); } else if (DRAWCROSS(normal_ind_on)) { XChangeGC(dpy, glyph_gc, GCForeground|GCBackground, &values); XmeDrawIndicator(dpy, drawable, glyph_gc, x, y, edge, edge, box_margin, normal_ind_on); } } break; } break; } case XmONE_OF_MANY: /* This value should have been normalized away! */ assert(FALSE); case XmONE_OF_MANY_DIAMOND: XmeDrawDiamond(dpy, drawable, top_gc, bot_gc, fill_gc, x, y, edge,edge, w->toggle.detail_shadow_thickness, margin); break; case XmONE_OF_MANY_ROUND: XmeDrawCircle(dpy, drawable, top_gc, bot_gc, fill_gc, x, y, edge, edge, w->toggle.detail_shadow_thickness, 1); break; } } else { /* The toggle indicator should be invisible. */ if (edge > 0) { /* use the arm GC in a menu if armed and enableEtchedInMenu is set */ if (Lab_IsMenupane(w) && etched_in && w->toggle.Armed) XFillRectangle(dpy, drawable, w->toggle.arm_GC, x, y, edge + 4, edge + 2); else XFillRectangle(dpy, drawable, w->toggle.background_gc, x, y, edge + 4, edge + 2); } } } /*************************************<->************************************* * * BorderHighlight * *************************************<->***********************************/ static void BorderHighlight( Widget wid ) { XmToggleButtonWidget tb = (XmToggleButtonWidget) wid ; XEvent * event = NULL; if (Lab_IsMenupane(tb)) { XmDisplay dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(wid)); Boolean etched_in = dpy->display.enable_etched_in_menu; Boolean already_armed = tb->toggle.Armed; tb->toggle.Armed = True; if ((etched_in) && ((tb->toggle.ind_on) || (!(tb->toggle.ind_on) && !(tb->toggle.fill_on_select)))) { DrawEtchedInMenu(tb); if (tb->toggle.ind_on) DrawToggle(tb); } XmeDrawShadows (XtDisplay (tb), XtWindow (tb), tb->primitive.top_shadow_GC, tb->primitive.bottom_shadow_GC, tb->primitive.highlight_thickness, tb->primitive.highlight_thickness, tb->core.width - 2 * tb->primitive.highlight_thickness, tb->core.height - 2 * tb->primitive.highlight_thickness, tb->primitive.shadow_thickness, etched_in ? XmSHADOW_IN : XmSHADOW_OUT); if (!already_armed && tb->toggle.arm_CB) { XFlush (XtDisplay (tb)); ToggleButtonCallback(tb, XmCR_ARM, tb->toggle.set, event); } } else { (*(xmLabelClassRec.primitive_class.border_highlight))((Widget) tb) ; } } /*************************************<->************************************* * * BorderUnhighlight * *************************************<->***********************************/ static void BorderUnhighlight( Widget wid ) { XmToggleButtonWidget tb = (XmToggleButtonWidget) wid ; XEvent * event = NULL; if (Lab_IsMenupane(tb)) { XmDisplay dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(wid)); Boolean etched_in = dpy->display.enable_etched_in_menu; Boolean already_armed = tb->toggle.Armed; tb -> toggle.Armed = FALSE; if ((etched_in) && ((tb->toggle.ind_on) || (!(tb->toggle.ind_on) && !(tb->toggle.fill_on_select)))) { DrawEtchedInMenu(tb); if (tb->toggle.ind_on) DrawToggle(tb); } XmeClearBorder (XtDisplay (tb), XtWindow (tb), tb->primitive.highlight_thickness, tb->primitive.highlight_thickness, tb->core.width - 2 * tb->primitive.highlight_thickness, tb->core.height - 2 * tb->primitive.highlight_thickness, tb->primitive.shadow_thickness); if (tb->toggle.Armed && tb->toggle.disarm_CB) { XFlush (XtDisplay (tb)); ToggleButtonCallback(tb, XmCR_DISARM, tb->toggle.set, event); } } else { (*(xmLabelClassRec.primitive_class.border_unhighlight))((Widget) tb) ; } } /* spb This action does not seem to be used anywhere */ /* Tue Apr 27 17:31:48 1993 */ /*************************************<->************************************* * * KeySelect * If the menu system traversal is enabled, do an activate and disarm * *************************************<->***********************************/ /* ARGSUSED */ static void KeySelect( Widget wid, XEvent *event, String *param, Cardinal *num_param ) { XmToggleButtonWidget tb = (XmToggleButtonWidget) wid ; XmToggleButtonCallbackStruct call_value; XmMenuSystemTrait menuSTrait; menuSTrait = (XmMenuSystemTrait) XmeTraitGet((XtPointer) XtClass(XtParent(tb)), XmQTmenuSystem); if (menuSTrait == NULL) return; if (!_XmIsEventUnique(event)) return; if (!_XmGetInDragMode((Widget)tb)) { if (tb->toggle.ind_on) DrawToggle(tb); else if (tb->toggle.fill_on_select && !Lab_IsPixmap(tb)) DrawToggleLabel(tb); if (Lab_IsPixmap(tb)) SetAndDisplayPixmap( tb, event, NULL); tb->toggle.Armed = FALSE; tb->toggle.set = (tb->toggle.set == TRUE) ? FALSE : TRUE; if (menuSTrait != NULL) menuSTrait->buttonPopdown(XtParent(tb), event); _XmRecordEvent(event); /* UNDOING this fix ... */ /* CR 8904: Notify value_changed before entry so that state is */ /* reported correctly even if the entry callback resets it. */ /* If the parent is menu system able, notify it about the select. */ if (menuSTrait != NULL) { call_value.reason = XmCR_VALUE_CHANGED; call_value.event = event; call_value.set = tb->toggle.set; menuSTrait->entryCallback(XtParent(tb), (Widget) tb, &call_value); } if (menuSTrait != NULL) menuSTrait->reparentToTearOffShell(XtParent(tb), event); if ((! tb->label.skipCallback) && (tb->toggle.value_changed_CB)) { XFlush(XtDisplay(tb)); ToggleButtonCallback(tb, XmCR_VALUE_CHANGED, tb->toggle.set, event); } } } /************************************************************************ * * Compute Space * ***********************************************************************/ static void ComputeSpace( XmToggleButtonWidget tb ) { int needed_width; int needed_height; /* Compute space for drawing toggle. */ needed_width = tb->label.TextRect.width + tb->label.margin_left + tb->label.margin_right + (2 * (tb->primitive.shadow_thickness + tb->primitive.highlight_thickness + tb->label.margin_width)); needed_height = tb->label.TextRect.height + tb->label.margin_top + tb->label.margin_bottom + (2 * (tb->primitive.shadow_thickness + tb->primitive.highlight_thickness + tb->label.margin_height)); if (needed_height > tb->core.height) if (tb->toggle.ind_on) tb->label.TextRect.y = tb->primitive.shadow_thickness + tb->primitive.highlight_thickness + tb->label.margin_height + tb->label.margin_top + ((tb->core.height - tb->label.margin_top - tb->label.margin_bottom - (2 * (tb->label.margin_height + tb->primitive.highlight_thickness + tb->primitive.shadow_thickness)) - tb->label.TextRect.height) / 2); if (LayoutIsRtoLP(tb)) { if ((needed_width > tb->core.width) || ((tb->label.alignment == XmALIGNMENT_BEGINNING) && (needed_width < tb->core.width)) || ((tb->label.alignment == XmALIGNMENT_CENTER) && (needed_width < tb->core.width) && (tb->core.width - needed_width < tb->label.margin_right)) || (needed_width == tb->core.width)) { if (tb->toggle.ind_on) tb->label.TextRect.x = tb->core.width - (tb->primitive.shadow_thickness + tb->primitive.highlight_thickness + tb->label.margin_width + tb->label.margin_right + tb->label.TextRect.width); } } else { if ((needed_width > tb->core.width) || ((tb->label.alignment == XmALIGNMENT_BEGINNING) && (needed_width < tb->core.width)) || ((tb->label.alignment == XmALIGNMENT_CENTER) && (needed_width < tb->core.width) && (tb->core.width - needed_width < tb->label.margin_left)) || (needed_width == tb->core.width)) { if (tb->toggle.ind_on) tb->label.TextRect.x = tb->primitive.shadow_thickness + tb->primitive.highlight_thickness + tb->label.margin_width + tb->label.margin_left; } } } /*************************************<->************************************* * * Redisplay (w, event, region) * Cause the widget, identified by w, to be redisplayed. * *************************************<->***********************************/ /*ARGUSED*/ static void Redisplay( Widget w, XEvent *event, Region region ) { register XmToggleButtonWidget tb = (XmToggleButtonWidget) w; if (! XtIsRealized(w) ) return; /* Fix CR #4884, D. Rand 6/4/92 */ ComputeSpace (tb); if (Lab_IsPixmap(tb)) SetAndDisplayPixmap(tb, event, region); else if (!tb->toggle.ind_on && tb->toggle.fill_on_select) DrawToggleLabel (tb); else { XtExposeProc expose; _XmProcessLock(); expose = xmLabelClassRec.core_class.expose; _XmProcessUnlock(); (* expose) (w, event, region); } if (tb->toggle.ind_on) { if (!(tb->toggle.Armed)) IsOn(tb) = tb->toggle.set; DrawToggle(tb); } if (Lab_IsMenupane(tb)) { XmDisplay dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(w)); Boolean etched_in = dpy -> display.enable_etched_in_menu; if ((tb->toggle.Armed) && (tb->primitive.shadow_thickness > 0)) XmeDrawShadows (XtDisplay (tb), XtWindow (tb), tb->primitive.top_shadow_GC, tb->primitive.bottom_shadow_GC, tb ->primitive.highlight_thickness, tb ->primitive.highlight_thickness, (int)tb->core.width-2*tb->primitive.highlight_thickness, (int)tb->core.height-2*tb->primitive.highlight_thickness, tb->primitive.shadow_thickness, etched_in ? XmSHADOW_IN : XmSHADOW_OUT); } else { DrawToggleShadow (tb); } } /************************************************************************** * * Resize(w, event) * **************************************************************************/ static void Resize( Widget w ) { register XmToggleButtonWidget tb = (XmToggleButtonWidget) w; /* BEGIN OSF Fix pir 1778 */ if (Lab_IsPixmap(w)) SetToggleSize(tb); else { XtWidgetProc resize; _XmProcessLock(); resize = xmLabelClassRec.core_class.resize; _XmProcessUnlock(); (* resize)( (Widget) tb); } /* END OSF Fix pir 1778 */ } /************************************************************************ * * SetValuesPrehook * ************************************************************************/ /*ARGSUSED*/ static Boolean SetValuesPrehook( Widget cw, /* unused */ Widget rw, /* unused */ Widget nw, ArgList args, /* unused */ Cardinal *num_args ) /* unused */ { XmToggleButtonWidget new_w = (XmToggleButtonWidget) nw ; /* CR 2990: Use XmNbuttonFontList as the default font. */ if (new_w->label.font == NULL) new_w->label.font = XmeGetDefaultRenderTable (nw, XmBUTTON_FONTLIST); return False; } /*************************************************************************** * * SetValues(current, request, new_w) * This is the set values procedure for the ToggleButton class. It is * called last (the set values rtnes for its superclasses are called * first). * *************************************<->***********************************/ /* ARGSUSED */ static Boolean SetValues( Widget current, Widget request, Widget new_w, ArgList args, Cardinal *num_args ) { XmToggleButtonWidget curcbox = (XmToggleButtonWidget) current; XmToggleButtonWidget reqcbox = (XmToggleButtonWidget) request; XmToggleButtonWidget newcbox = (XmToggleButtonWidget) new_w; Boolean flag = FALSE; /* our return value */ XtWidgetProc resize; /* CR 2337: Preserve the user's margins. */ if (curcbox->label.margin_right != reqcbox->label.margin_right) newcbox->toggle.ind_right_delta = 0; if (curcbox->label.margin_left != reqcbox->label.margin_left) newcbox->toggle.ind_left_delta = 0; if (curcbox->label.margin_top != reqcbox->label.margin_top) newcbox->toggle.ind_top_delta = 0; if (curcbox->label.margin_bottom != reqcbox->label.margin_bottom) newcbox->toggle.ind_bottom_delta = 0; /********************************************************************** * Calculate the window size: The assumption here is that if * the width and height are the same in the new and current instance * record that those fields were not changed with set values. Therefore * its okay to recompute the necessary width and height. However, if * the new and current do have different width/heights then leave them * alone because that's what the user wants. *********************************************************************/ _XmProcessLock(); resize = xmLabelClassRec.core_class.resize; _XmProcessUnlock(); /* Use the On pixmaps if no Indeterminate pixmaps are found. */ if (IsNull(PixmapInd(newcbox)) && !IsNull(PixmapOn(newcbox))) PixmapInd(newcbox) = PixmapOn(newcbox); if (IsNull(PixmapInsenInd(newcbox)) && !IsNull(PixmapInsenOn(newcbox))) PixmapInsenInd(newcbox) = PixmapInsenOn(newcbox); /* Use the On pixmap if no Off pixmap is found. */ if (IsNull(PixmapOff(newcbox)) && !IsNull(PixmapOn(newcbox))) { PixmapOff(newcbox) = PixmapOn(newcbox); if ((newcbox->label.recompute_size) && (request->core.width == current->core.width)) new_w->core.width = 0; if ((newcbox->label.recompute_size) && (request->core.height == current->core.height)) new_w->core.height = 0; _XmCalcLabelDimensions(new_w); (* resize)( (Widget) new_w); } /* Use the insensitive On pixmap if no insensitive Off pixmap is found. */ if (IsNull(PixmapInsenOff(newcbox)) && !IsNull(PixmapInsenOn(newcbox))) { PixmapInsenOff(newcbox) = PixmapInsenOn(newcbox); if ((newcbox->label.recompute_size) && (request->core.width == current->core.width)) new_w->core.width = 0; if ((newcbox->label.recompute_size) && (request->core.height == current->core.height)) new_w->core.height = 0; _XmCalcLabelDimensions(new_w); (* resize)( (Widget) new_w); } /* BEGIN OSF Fix pir 1778 */ /* Have to reset the TextRect width because label's resize will have * mucked with it. */ if (Lab_IsPixmap(newcbox) && (!IsNull(PixmapOff(newcbox)) || !IsNull(PixmapInsenOff(newcbox)) || !IsNull(PixmapOn(newcbox)) || !IsNull(PixmapInsenOn(newcbox)) || !IsNull(PixmapInd(newcbox)) || !IsNull(PixmapInsenInd(newcbox)))) { if ((newcbox->label.recompute_size)) { if (request->core.width == current->core.width) new_w->core.width = 0; if (request->core.height == current->core.height) new_w->core.height = 0; } SetToggleSize(newcbox); } /* END OSF Fix pir 1778 */ /* CR 9922: Changing fillOnSelect requires a redraw. */ if (newcbox->toggle.fill_on_select != curcbox->toggle.fill_on_select) { flag = TRUE; } if ((newcbox->label._label != curcbox->label._label) || (PixmapOff(newcbox) != PixmapOff(curcbox)) || (newcbox->label.font != curcbox->label.font) || (newcbox->toggle.spacing != curcbox->toggle.spacing) || (PixmapOn(newcbox) != PixmapOn(curcbox)) || (PixmapInsenOn(newcbox) != PixmapInsenOn(curcbox)) || (PixmapInd(newcbox) != PixmapInd(curcbox)) || (PixmapInsenInd(newcbox) != PixmapInsenInd(curcbox)) || (newcbox->toggle.ind_on != curcbox->toggle.ind_on) || (newcbox->toggle.indicator_dim != curcbox->toggle.indicator_dim) || (Lab_IsPixmap(newcbox) != Lab_IsPixmap(curcbox))) { int right_delta = 0; /* Our desired margin adjustments. */ int left_delta = 0; int top_delta = 0; int bottom_delta = 0; if (newcbox->label.recompute_size) { if (request->core.width == current->core.width) new_w->core.width = 0; if (request->core.height == current->core.height) new_w->core.height = 0; } if (Lab_IsPixmap(newcbox) && ((PixmapOn(newcbox) != PixmapOn(curcbox)) || (PixmapInsenOn(newcbox) != PixmapInsenOn(curcbox)) || (PixmapInd(newcbox) != PixmapInd(curcbox)) || (PixmapInsenInd(newcbox) != PixmapInsenInd(curcbox))) ) { _XmCalcLabelDimensions(new_w); /* OSF Fix pir 1778 */ SetToggleSize(newcbox); } newcbox->toggle.indicator_set = curcbox->toggle.indicator_set; if (newcbox->toggle.indicator_dim != curcbox->toggle.indicator_dim) { newcbox->toggle.indicator_set = TRUE; } /* CR 8415: Honor explicit requests for XmNindicatorSize. */ if (!(newcbox->toggle.indicator_set) && (newcbox->toggle.indicator_dim == curcbox->toggle.indicator_dim)) { if ((Lab_IsPixmap(newcbox) != Lab_IsPixmap(curcbox)) || (newcbox->label._label != curcbox->label._label) || (PixmapOff(newcbox) != PixmapOff(curcbox)) || (newcbox->label.font != curcbox->label.font) || (newcbox->toggle.ind_on != curcbox->toggle.ind_on)) { if Lab_IsPixmap(new_w) { if (!IsNull(PixmapOff(newcbox)) || !IsNull(PixmapInsenOff(newcbox)) || !IsNull(PixmapOn(newcbox)) || !IsNull(PixmapInsenOn(newcbox)) || !IsNull(PixmapInd(newcbox)) || !IsNull(PixmapInsenInd(newcbox))) if (newcbox->label.TextRect.height < 13) newcbox->toggle.indicator_dim = newcbox->label.TextRect.height; else newcbox->toggle.indicator_dim = 13 + (newcbox->label.TextRect.height/13); else newcbox->toggle.indicator_dim = XmDEFAULT_INDICATOR_DIM; } else { Dimension height; int line_count; height = XmStringHeight (newcbox->label.font, newcbox->label._label); line_count = XmStringLineCount (newcbox->label._label); /* * CR 5203 - Make the calculation for the * indicator_dim be the same as in the Initialize * procedure, i.e. Popup and Pulldown menus should * have smaller indicators. */ if (line_count < 1) line_count = 1; if (Lab_IsMenupane(newcbox)) newcbox->toggle.indicator_dim = MAX(XmDEFAULT_INDICATOR_DIM, (height / ((Dimension)line_count)) * 2/3); else newcbox->toggle.indicator_dim = MAX(XmDEFAULT_INDICATOR_DIM, height / ((Dimension)line_count)); /* End 5203 Fix */ } } } if (newcbox->toggle.ind_on) { /* * Fix CR 5568 - If the indicator is on and the user has changed the * indicator dimension, calculate the new top and bottom * margins in a place where they can effect the core width * and height. */ /* Recompute the Top and bottom margins and the height of the text * rectangle to accommodate the size of toggle indicator. * if (we are given a new toggleIndicator size) * { if (user has given new top or bottom margin) * { compute to accomodate new toggle button size; } * else (user has set new top/bottom margin) * { Recompute margin to accommodate new IndicatorSize; } * } */ if (newcbox->toggle.indicator_dim != curcbox->toggle.indicator_dim) { int maxIndicatorSize = (int) (newcbox->toggle.indicator_dim) + 2*Xm3D_ENHANCE_PIXEL; int boxSize = ((int) newcbox->label.TextRect.height + (int) newcbox->label.margin_top + (int) newcbox->label.margin_bottom); top_delta = bottom_delta = (maxIndicatorSize - boxSize) / 2; } /* End fix CR 5568 */ if (LayoutIsRtoLP(newcbox)) right_delta = (newcbox->toggle.indicator_dim + newcbox->toggle.spacing - newcbox->label.margin_right); else left_delta = (newcbox->toggle.indicator_dim + newcbox->toggle.spacing - newcbox->label.margin_left); } else if (curcbox->toggle.ind_on) { /* CR 2337: Redisplay when the indicator is turned off. */ flag = TRUE; top_delta = -newcbox->toggle.ind_top_delta; bottom_delta = -newcbox->toggle.ind_bottom_delta; if (LayoutIsRtoLP(newcbox)) right_delta = -newcbox->toggle.ind_right_delta; else left_delta = -newcbox->toggle.ind_left_delta; } /* CR 2337: Let the toggle button shrink if necessary. */ if (right_delta || left_delta || top_delta || bottom_delta) { flag = TRUE; /* Adjust vertical margins based on the indicator. */ if ((int)newcbox->toggle.ind_top_delta + top_delta > 0) { newcbox->label.margin_top += top_delta; newcbox->toggle.ind_top_delta += top_delta; } else { newcbox->label.margin_top -= newcbox->toggle.ind_top_delta; newcbox->toggle.ind_top_delta = 0; } if ((int)newcbox->toggle.ind_bottom_delta + bottom_delta > 0) { newcbox->label.margin_bottom += bottom_delta; newcbox->toggle.ind_bottom_delta += bottom_delta; } else { newcbox->label.margin_bottom -= newcbox->toggle.ind_bottom_delta; newcbox->toggle.ind_bottom_delta = 0; } /* Adjust horizontal margins based on the indicator. */ if (LayoutIsRtoLP(newcbox)) { if ((int)newcbox->toggle.ind_right_delta + right_delta > 0) { newcbox->label.margin_right += right_delta; newcbox->toggle.ind_right_delta += right_delta; } else { newcbox->label.margin_right -= newcbox->toggle.ind_right_delta; newcbox->toggle.ind_right_delta = 0; } } else { if ((int)newcbox->toggle.ind_left_delta + left_delta > 0) { newcbox->label.margin_left += left_delta; newcbox->toggle.ind_left_delta += left_delta; } else { newcbox->label.margin_left -= newcbox->toggle.ind_left_delta; newcbox->toggle.ind_left_delta = 0; } } /* Realign the label. */ if (!newcbox->label.recompute_size) (* resize) ((Widget) new_w); } if (newcbox->label.recompute_size) { if (request->core.width == current->core.width) new_w->core.width = 0; if (request->core.height == current->core.height) new_w->core.height = 0; } if (new_w->core.width == 0) { newcbox->core.width = newcbox->label.TextRect.width + newcbox->label.margin_left + newcbox->label.margin_right + 2 * (newcbox->primitive.highlight_thickness + newcbox->primitive.shadow_thickness + newcbox->label.margin_width); if (newcbox->core.width == 0) newcbox->core.width = 1; flag = TRUE; } if (new_w->core.height == 0) { newcbox->core.height = MAX(newcbox->toggle.indicator_dim, newcbox->label.TextRect.height + 2 * newcbox->label.margin_height + newcbox->label.margin_top + newcbox->label.margin_bottom) + 2 * (newcbox->primitive.highlight_thickness + newcbox->primitive.shadow_thickness); if (newcbox->core.height == 0) newcbox->core.height = 1; flag = TRUE; } } if ((newcbox->primitive.foreground != curcbox->primitive.foreground) || (newcbox->core.background_pixel != curcbox->core.background_pixel) || (newcbox->toggle.select_color != curcbox->toggle.select_color)) { XtReleaseGC( (Widget) curcbox, curcbox->toggle.select_GC); XtReleaseGC( (Widget) curcbox, curcbox->toggle.background_gc); XtReleaseGC( (Widget) curcbox, curcbox->toggle.indeterminate_GC); XtReleaseGC( (Widget) curcbox, curcbox->toggle.indeterminate_box_GC); newcbox->toggle.reversed_select = (newcbox->toggle.select_color == XmREVERSED_GROUND_COLORS); if (newcbox->toggle.select_color == XmDEFAULT_SELECT_COLOR) { /* CR 9923: Copy all bytes of the resulting pixel. */ XrmValue value; DefaultSelectColor((Widget)newcbox, XtOffsetOf(XmToggleButtonRec,toggle.select_color), &value); assert(value.size == sizeof(Pixel)); newcbox->toggle.select_color = *((Pixel*) value.addr); } else if (newcbox->toggle.select_color == XmREVERSED_GROUND_COLORS) { newcbox->toggle.select_color = newcbox->primitive.foreground; } else if (newcbox->toggle.select_color == XmHIGHLIGHT_COLOR) { newcbox->toggle.select_color = newcbox->primitive.highlight_color; } GetGC(newcbox); flag = TRUE; } if (newcbox->toggle.unselect_color != curcbox->toggle.unselect_color) { XtReleaseGC ((Widget) curcbox, curcbox->toggle.unselect_GC); GetUnselectGC(newcbox); flag = TRUE; } if ((curcbox->toggle.ind_type != newcbox->toggle.ind_type) && (!XmRepTypeValidValue(XmRID_INDICATOR_TYPE, newcbox->toggle.ind_type, (Widget) newcbox))) { newcbox->toggle.ind_type = curcbox->toggle.ind_type; } if (curcbox->toggle.set != newcbox->toggle.set) { if ((newcbox->toggle.toggle_mode == XmTOGGLE_BOOLEAN) && (newcbox->toggle.set == XmINDETERMINATE)) { newcbox->toggle.set = curcbox->toggle.set; } else { IsOn(newcbox) = newcbox->toggle.set; if (flag == False && XtIsRealized((Widget)newcbox)) { if (newcbox->toggle.ind_on) { DrawToggle (newcbox); if (Lab_IsPixmap(newcbox)) SetAndDisplayPixmap(newcbox, NULL, NULL); } else { /* Begin fixing OSF 5946 */ if (newcbox->primitive.shadow_thickness > 0) DrawToggleShadow (newcbox); if (newcbox->toggle.fill_on_select && !Lab_IsPixmap(newcbox)) DrawToggleLabel (newcbox); if (Lab_IsPixmap(newcbox)) { SetAndDisplayPixmap(newcbox, NULL, NULL); flag = True; } /* End fixing OSF 5946 */ } } } } if ((curcbox->toggle.ind_type != newcbox->toggle.ind_type) || ( (curcbox->toggle.visible != newcbox->toggle.visible) && (XmUNSET == newcbox->toggle.set)) ) { flag = True; } /* One-of-many forces boolean mode. */ if (IsOneOfMany(newcbox->toggle.ind_type) && (newcbox->toggle.toggle_mode == XmTOGGLE_INDETERMINATE)) { newcbox->toggle.toggle_mode = XmTOGGLE_BOOLEAN; } /* * Transition between True/False is easy. Transition from * indetermine is done by setting the toggle to False. */ if ((curcbox->toggle.toggle_mode != newcbox->toggle.toggle_mode) && (newcbox->toggle.toggle_mode == XmTOGGLE_BOOLEAN) && (newcbox->toggle.set == XmINDETERMINATE)) { newcbox->toggle.visual_set = newcbox->toggle.set = XmUNSET; flag = True; } return(flag); } /*************************************************************** * * XmToggleButtonGetState * This function gets the state of the toggle widget. * ***************************************************************/ Boolean XmToggleButtonGetState( Widget w ) { XmToggleButtonWidget tw = (XmToggleButtonWidget) w; Boolean ret_val; XtAppContext app = XtWidgetToApplicationContext(w); if (XmIsGadget(w)) return XmToggleButtonGadgetGetState(w); _XmAppLock(app); ret_val = tw->toggle.set; _XmAppUnlock(app); return (ret_val); } /**************************************************************** * * XmTogglebuttonSetState * This function sets the state of the toggle widget. * ****************************************************************/ void XmToggleButtonSetState( Widget w, #if NeedWidePrototypes int bnewstate, int notify ) #else Boolean bnewstate, Boolean notify ) #endif /* NeedWidePrototypes */ { XmToggleButtonWidget tw = (XmToggleButtonWidget) w; XmMenuSystemTrait menuSTrait; XtAppContext app = XtWidgetToApplicationContext(w); XmToggleButtonState newstate; if (XmIsGadget(w)) { XmToggleButtonGadgetSetState(w, bnewstate, notify); return; } _XmAppLock(app); /* toggel.set is enum type, not Boolean */ newstate = (bnewstate == XmSET)? XmSET : XmUNSET; if (tw->toggle.set != newstate) { tw->toggle.set = newstate; IsOn(tw) = newstate; if (XtIsRealized ((Widget)tw)) { if (tw->toggle.ind_on) DrawToggle(tw); else { if (tw->primitive.shadow_thickness > 0) DrawToggleShadow (tw); if (tw->toggle.fill_on_select && !Lab_IsPixmap(tw)) DrawToggleLabel (tw); } if (Lab_IsPixmap(tw)) SetAndDisplayPixmap( tw, NULL, NULL); } if (notify) { /* UNDOING this fix ... */ /* CR 8904: Notify value_changed before entry so that state is */ /* reported correctly even if the entry callback resets it. */ menuSTrait = (XmMenuSystemTrait) XmeTraitGet((XtPointer) XtClass(XtParent(tw)), XmQTmenuSystem); if (menuSTrait != NULL) { XmToggleButtonCallbackStruct call_value; call_value.reason = XmCR_VALUE_CHANGED; call_value.event = NULL; call_value.set = tw->toggle.set; menuSTrait->entryCallback(XtParent(tw), (Widget)tw, &call_value); } if ((! tw->label.skipCallback) && (tw->toggle.value_changed_CB)) { XFlush(XtDisplay(tw)); ToggleButtonCallback(tw, XmCR_VALUE_CHANGED, tw->toggle.set, NULL); } } } _XmAppUnlock(app); } /**************************************************************** * * XmToggleButtonSetValue * This function sets the state of the toggle widget. * ****************************************************************/ Boolean XmToggleButtonSetValue( Widget w, #if NeedWidePrototypes int newstate, int notify ) #else XmToggleButtonState newstate, Boolean notify ) #endif /* NeedWidePrototypes */ { XmToggleButtonWidget tw = (XmToggleButtonWidget) w; XtAppContext app = XtWidgetToApplicationContext(w); if (XmIsGadget(w)) return XmToggleButtonGadgetSetValue(w, newstate, notify); _XmAppLock(app); /* Can't set third state if we aren't in three state mode. */ if ((newstate == XmINDETERMINATE) && (tw->toggle.toggle_mode != XmTOGGLE_INDETERMINATE)) { _XmAppUnlock(app); return False; } if (tw->toggle.set != newstate) { tw->toggle.set = tw->toggle.visual_set = newstate; if (XtIsRealized ((Widget)tw)) { if (tw->toggle.ind_on) DrawToggle(tw); else { if (tw->primitive.shadow_thickness > 0) DrawToggleShadow (tw); if (tw->toggle.fill_on_select && !Lab_IsPixmap(tw)) DrawToggleLabel (tw); } if (Lab_IsPixmap(tw)) SetAndDisplayPixmap( tw, NULL, NULL); } if (notify) { /* If the parent is a RowColumn, notify it about the select. */ if (XmIsRowColumn(XtParent(tw))) { XmToggleButtonCallbackStruct call_value; call_value.reason = XmCR_VALUE_CHANGED; call_value.event = NULL; call_value.set = tw->toggle.set; (* xmLabelClassRec.label_class.menuProcs) (XmMENU_CALLBACK, XtParent(tw), FALSE, tw, &call_value); } if ((! tw->label.skipCallback) && (tw->toggle.value_changed_CB)) { XFlush(XtDisplay(tw)); ToggleButtonCallback(tw, XmCR_VALUE_CHANGED, tw->toggle.set, NULL); } } } _XmAppUnlock(app); return True; } /*********************************************************************** * * XmCreateToggleButton * Creates an instance of a togglebutton and returns the widget id. * ************************************************************************/ Widget XmCreateToggleButton( Widget parent, char *name, Arg *arglist, Cardinal argCount ) { return XtCreateWidget(name, xmToggleButtonWidgetClass, parent, arglist, argCount); } /* * DrawToggleShadow (tb) * - Should be called only if ToggleShadow are to be drawn ; * if the IndicatorOn resource is set to false top and bottom shadows * will be switched depending on whether the Toggle is selected or * unselected. * No need to call the routine if shadow_thickness is 0. */ static void DrawToggleShadow( XmToggleButtonWidget tb ) { GC top_gc, bot_gc; int width, height; int hilite_thickness; if (tb->toggle.ind_on || (IsOn(tb) == XmUNSET)) { top_gc = tb->primitive.top_shadow_GC; bot_gc = tb->primitive.bottom_shadow_GC; } else if (IsOn(tb) == XmINDETERMINATE) { top_gc = bot_gc = tb->toggle.indeterminate_box_GC; } else { top_gc = tb->primitive.bottom_shadow_GC; bot_gc = tb->primitive.top_shadow_GC; } hilite_thickness = tb->primitive.highlight_thickness; width = (int) (tb->core.width - (hilite_thickness << 1)); height = (int) (tb->core.height - (hilite_thickness << 1)); XmeDrawShadows (XtDisplay (tb), XtWindow (tb), top_gc, bot_gc, hilite_thickness, hilite_thickness, width, height, tb->primitive.shadow_thickness, XmSHADOW_OUT); } /* * DrawToggleLabel (tb) * Called when XmNindicatorOn is FALSE and XmNfillOnSelect is TRUE. * Fill toggle with selectColor or background depending on toggle * value, and draw label. */ static void DrawToggleLabel( XmToggleButtonWidget tb ) { Dimension margin = (tb->primitive.highlight_thickness + tb->primitive.shadow_thickness); Position fx = margin; Position fy = margin; int fw = tb->core.width - 2 * margin; int fh = tb->core.height - 2 * margin; Boolean restore_gc = False; GC tmp_gc = None, fill_gc; if (tb->primitive.top_shadow_color == tb->toggle.select_color || tb->primitive.bottom_shadow_color == tb->toggle.select_color) { fx += 1; fy += 1; fw -= 2; fh -= 2; } if (fw < 0 || fh < 0) return; switch (tb->toggle.visual_set) { case XmUNSET: fill_gc = tb->toggle.unselect_GC; break; case XmSET: fill_gc = tb->toggle.select_GC; break; case XmINDETERMINATE: { XGCValues values; /* Fetch the select_color GetGC() actually used. */ XGetGCValues(XtDisplay(tb), tb->toggle.select_GC, GCForeground, &values); values.background = tb->toggle.unselect_color; XChangeGC(XtDisplay((Widget)tb), tb->toggle.indeterminate_GC, GCForeground|GCBackground, &values); fill_gc = tb->toggle.indeterminate_GC; break; } default: assert(False); return; } XFillRectangle (XtDisplay(tb), XtWindow(tb), fill_gc, fx, fy, fw, fh); if ((tb->primitive.foreground == tb->toggle.select_color) && (IsOn(tb) == XmSET)) { tmp_gc = tb->label.normal_GC; tb->label.normal_GC = tb->toggle.background_gc; restore_gc = True; } { XtExposeProc expose; _XmProcessLock(); expose = xmLabelClassRec.core_class.expose; _XmProcessUnlock(); (* expose) ((Widget) tb, NULL, NULL); } if (restore_gc) { /* CR 9791: Label's normal_gc has a dynamic clip_mask. */ XSetClipMask(XtDisplay(tb), tb->toggle.background_gc, None); tb->label.normal_GC = tmp_gc; } } /* * DrawEtchedInMenu (tb) * Called when in a Menu and EtchedInMenu is TRUE. * And when XmNindicatorOn is FALSE and XmNfillOnSelect is FALSE; * or when XmNindicatorOn is TRUE. * Fill background with the arm_gc and draw label. */ static void DrawEtchedInMenu( XmToggleButtonWidget tb ) { Dimension margin = (tb->primitive.highlight_thickness + tb->primitive.shadow_thickness); Position fx = margin; Position fy = margin; int fw = tb->core.width - 2 * margin; int fh = tb->core.height - 2 * margin; Boolean restore_gc = False; GC tmp_gc = None; XmDisplay dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(tb)); Boolean etched_in = dpy->display.enable_etched_in_menu; if (tb->primitive.top_shadow_color == tb->toggle.select_color || tb->primitive.bottom_shadow_color == tb->toggle.select_color) { fx += 1; fy += 1; fw -= 2; fh -= 2; } if (fw < 0 || fh < 0) return; XFillRectangle (XtDisplay(tb), XtWindow(tb), tb->toggle.Armed ? tb->toggle.arm_GC : tb->toggle.background_gc, fx, fy, fw, fh); if (tb->toggle.Armed) { Pixel select_pix; XmGetColors(XtScreen(tb), tb->core.colormap, tb->core.background_pixel, NULL, NULL, NULL, &select_pix); if (tb->primitive.foreground == select_pix) { tmp_gc = tb->label.normal_GC; tb->label.normal_GC = tb->toggle.background_gc; restore_gc = True; } } { XtExposeProc expose; _XmProcessLock(); expose = xmLabelClassRec.core_class.expose; _XmProcessUnlock(); (* expose) ((Widget) tb, NULL, NULL); } if (restore_gc) { XSetClipMask(XtDisplay(tb), tb->toggle.background_gc, None); tb->label.normal_GC = tmp_gc; } } /* BEGIN OSF Fix pir 1778 */ /************************************************************************* * * SetToggleSize(newtb) * Set size properly when XmNselectPixmap or XmNselectInsensitivePixmaps * are set in addition to the corresponding labelPixmaps. Have to pick * the largest dimensions. * ************************************************************************/ static void SetToggleSize( XmToggleButtonWidget newtb) { unsigned int maxW, maxH; unsigned int tmpW, tmpH; maxW = maxH = tmpW = tmpH = 0; /* We know it's a pixmap so find out how how big it is */ if (XtIsSensitive((Widget) newtb)) { if (!IsNull(PixmapOn(newtb))) { XmeGetPixmapData(XtScreen(newtb), PixmapOn(newtb), NULL, NULL, NULL, NULL, NULL, NULL, &tmpW, &tmpH); ASSIGN_MAX(maxW, tmpW); ASSIGN_MAX(maxH, tmpH); } if (!IsNull(PixmapOff(newtb))) { XmeGetPixmapData(XtScreen(newtb), PixmapOff(newtb), NULL, NULL, NULL, NULL, NULL, NULL, &tmpW, &tmpH); ASSIGN_MAX(maxW, tmpW); ASSIGN_MAX(maxH, tmpH); } if (!IsNull(PixmapInd(newtb))) { XmeGetPixmapData(XtScreen(newtb), PixmapInd(newtb), NULL, NULL, NULL, NULL, NULL, NULL, &tmpW, &tmpH); ASSIGN_MAX(maxW, tmpW); ASSIGN_MAX(maxH, tmpH); } } else { if (!IsNull(PixmapInsenOn(newtb))) { XmeGetPixmapData(XtScreen(newtb), PixmapInsenOn(newtb), NULL, NULL, NULL, NULL, NULL, NULL, &tmpW, &tmpH); ASSIGN_MAX(maxW, tmpW); ASSIGN_MAX(maxH, tmpH); } if (!IsNull(PixmapInsenOff(newtb))) { XmeGetPixmapData(XtScreen(newtb), PixmapInsenOff(newtb), NULL, NULL, NULL, NULL, NULL, NULL, &tmpW, &tmpH); ASSIGN_MAX(maxW, tmpW); ASSIGN_MAX(maxH, tmpH); } if (!IsNull(PixmapInsenInd(newtb))) { XmeGetPixmapData(XtScreen(newtb), PixmapInsenInd(newtb), NULL, NULL, NULL, NULL, NULL, NULL, &tmpW, &tmpH); ASSIGN_MAX(maxW, tmpW); ASSIGN_MAX(maxH, tmpH); } } newtb->label.TextRect.width = (unsigned short) maxW; newtb->label.TextRect.height = (unsigned short) maxH; /* Invoke Label's SetSize procedure. */ { XtWidgetProc resize; _XmProcessLock(); resize = xmLabelClassRec.core_class.resize; _XmProcessUnlock(); (* resize) ((Widget) newtb); } } /* END OSF Fix pir 1778 */ /* * DefaultSelectColor - an XtResourceDefaultProc for generating the * default select color. This may require examining the * XmNindicatorType and XmNhighlightColor resources, which will * happen to have real values only because they appear before * XmNselectColor in the resource list. */ static void DefaultSelectColor(Widget widget, int offset, XrmValue *value) { XmToggleButtonWidget tb = (XmToggleButtonWidget) widget; Boolean force_highlight = FALSE; XmDisplay xm_dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(widget)); Boolean enable_toggle_color = xm_dpy->display.enable_toggle_color; if (enable_toggle_color) { /* This code may misbehave for erroneous ind_type values. */ if (IsOneOfMany(tb->toggle.ind_type)) { force_highlight = TRUE; } else if ((tb->toggle.ind_type == XmINVALID_TYPE) && XmIsRowColumn(XtParent(widget))) { XtVaGetValues(XtParent(widget), XmNradioBehavior, &force_highlight, NULL); } } if (force_highlight) { value->size = sizeof(tb->primitive.highlight_color); value->addr = (char *) &tb->primitive.highlight_color; } else _XmSelectColorDefault(widget, offset, value); } /* * NormalizeIndOn - return the normalized value of XmNindicatorOn, * replacing XmINDICATOR_FILL and XmINDICATOR_BOX with the proper * absolute values. */ static unsigned char NormalizeIndOn(XmToggleButtonWidget tb) { unsigned char value = tb->toggle.ind_on; /* Convert XmINDICATOR_FILL to XmINDICATOR_CHECK_BOX? */ if (value == XmINDICATOR_FILL) { /* This routine may be called frequently, so reach directly into */ /* the XmDisplay rather than calling XtGetValues. */ XmDisplay xm_dpy = (XmDisplay) XmGetXmDisplay(XtDisplay((Widget) tb)); if (xm_dpy->display.enable_toggle_visual) value = XmINDICATOR_CHECK_BOX; } /* Convert XmINDICATOR_BOX to XmINDICATOR_3D_BOX (XmINDICATOR_FILL). */ else if (value == XmINDICATOR_BOX) { value = XmINDICATOR_3D_BOX; } return value; } /* * NormalizeIndType - return the normalized value of XmNindicatorType, * replacing XmONE_OF_MANY with the proper absolute value. */ static unsigned char NormalizeIndType(XmToggleButtonWidget tb) { unsigned char value = tb->toggle.ind_type; if (value == XmONE_OF_MANY) { /* This routine may be called frequently, so reach directly into */ /* the XmDisplay rather than calling XtGetValues. */ XmDisplay xm_dpy = (XmDisplay) XmGetXmDisplay(XtDisplay((Widget) tb)); if (xm_dpy->display.enable_toggle_visual) value = XmONE_OF_MANY_ROUND; else value = XmONE_OF_MANY_DIAMOND; } return value; }