/*
* Motif
*
* Copyright (c) 1987-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these librararies and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
/*
* HISTORY
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#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 <stdio.h>
#include "XmI.h"
#include <X11/ShellP.h>
#include <Xm/BaseClassP.h>
#include <Xm/CascadeB.h>
#include <Xm/DisplayP.h>
#include <Xm/DrawP.h>
#include <Xm/ManagerP.h>
#include <Xm/MenuT.h>
#include <Xm/ToggleBG.h>
#include <Xm/ToggleBP.h>
#include <Xm/TraitP.h>
#include <Xm/TransltnsP.h>
#include <Xm/VaSimpleP.h>
#include "ColorI.h"
#include "LabelI.h"
#include "MenuProcI.h"
#include "MenuStateI.h"
#include "MenuUtilI.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) || Lab_IsPixmapAndText(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) || Lab_IsPixmapAndText(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 ;
XmToggleButtonCallbackStruct call_value;
Boolean hit;
XmMenuSystemTrait menuSTrait;
Boolean radio = TRUE, always = TRUE;
if (tb->toggle.Armed == FALSE)
return;
tb->toggle.Armed = FALSE;
if (XmIsRowColumn(XtParent(tb))) {
XtVaGetValues(XtParent(tb),
XmNradioBehavior, &radio,
XmNradioAlwaysOne, &always,
NULL);
}
/* 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);
}
}
}
/**********************************************************************
*
* 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
* <Key> Return and a <Key> 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;
Boolean radio = TRUE, always = TRUE, no_change;
if (XmIsRowColumn(XtParent(tb))) {
XtVaGetValues(XtParent(tb),
XmNradioBehavior, &radio,
XmNradioAlwaysOne, &always,
NULL);
}
no_change = False;
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 (!no_change) /* skip toggle for buttons already turned on */
{
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) || Lab_IsPixmapAndText(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) || Lab_IsPixmapAndText(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);
}
if (!no_change)
{
/* 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) || Lab_IsPixmapAndText(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) || Lab_IsPixmapAndText(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
{
/* Center indicator vertically next to the first line of text. */
int fudge = Xm3D_ENHANCE_PIXEL;
Dimension text_height;
int line_count, height_diff;
text_height = XmStringHeight(w->label.font, w->label._label);
if ((line_count = XmStringLineCount(w->label._label)) < 1)
line_count = 1;
height_diff = ((int)text_height / line_count) -
(int)w->toggle.indicator_dim;
if (height_diff < 0)
height_diff = 0;
y = w->label.TextRect.y + (height_diff / 2);
/* 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:
#ifdef FIX_1402
XmeDrawCircle(dpy, drawable, top_gc, bot_gc, fill_gc, x, y,
edge, edge, w->toggle.detail_shadow_thickness, margin);
#else
XmeDrawCircle(dpy, drawable, top_gc, bot_gc, fill_gc, x, y,
edge, edge, w->toggle.detail_shadow_thickness, 1);
#endif
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) || Lab_IsPixmapAndText(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) || Lab_IsPixmapAndText(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)) ||
(Lab_IsPixmapAndText(newcbox) != Lab_IsPixmapAndText(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)) ||
(Lab_IsPixmapAndText(newcbox) != Lab_IsPixmapAndText(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) || Lab_IsPixmapAndText(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) || Lab_IsPixmapAndText(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) || Lab_IsPixmapAndText(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) || Lab_IsPixmapAndText(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) || Lab_IsPixmapAndText(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);
}
Widget
XmVaCreateToggleButton(
Widget parent,
char *name,
...)
{
register Widget w;
va_list var;
int count;
Va_start(var,name);
count = XmeCountVaListSimple(var);
va_end(var);
Va_start(var, name);
w = XmeVLCreateWidget(name,
xmToggleButtonWidgetClass,
parent, False,
var, count);
va_end(var);
return w;
}
Widget
XmVaCreateManagedToggleButton(
Widget parent,
char *name,
...)
{
Widget w = NULL;
va_list var;
int count;
Va_start(var, name);
count = XmeCountVaListSimple(var);
va_end(var);
Va_start(var, name);
w = XmeVLCreateWidget(name,
xmToggleButtonWidgetClass,
parent, True,
var, count);
va_end(var);
return w;
}
/*
* 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;
#ifdef FIX_1395
Pixel tmpc = tb->core.background_pixel; /* Save bg color */
/* Changing label background color if button toggled */
if (tb->toggle.visual_set == XmSET && !Lab_IsMenupane(tb))
XSetWindowBackground(XtDisplay(tb), XtWindow(tb), tb->toggle.select_color);
#endif
_XmProcessLock();
expose = xmLabelClassRec.core_class.expose;
_XmProcessUnlock();
(* expose) ((Widget) tb, NULL, NULL);
#ifdef FIX_1395
/* restore default bg color */
if (tb->toggle.visual_set == XmSET && !Lab_IsMenupane(tb) )
XSetWindowBackground(XtDisplay(tb), XtWindow(tb), tmpc);
#endif
}
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;
Pixel select_pix, tmpc;
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)
{
tmpc = tb->core.background_pixel;
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;
#ifdef FIX_1395
if (tb->toggle.Armed)
{
XSetWindowBackground(XtDisplay(tb), XtWindow(tb), select_pix);
}
else
{
XSetWindowBackground(XtDisplay(tb), XtWindow(tb), tb->core.background_pixel);
}
#endif
_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;
}