/* $TOG: SpinB.c /main/27 1999/04/16 08:48:58 mgreess $ */ /* * @OPENGROUP_COPYRIGHT@ * COPYRIGHT NOTICE * Copyright (c) 1990, 1991, 1992, 1993 Open Software Foundation, Inc. * Copyright (c) 1996, 1997, 1998, 1999, 2000 The Open Group * ALL RIGHTS RESERVED (MOTIF). See the file named COPYRIGHT.MOTIF for * the full copyright text. * * This software is subject to an open license. It may only be * used on, with or for operating systems which are themselves open * source systems. You must contact The Open Group for a license * allowing distribution and sublicensing of this software on, with, * or for operating systems which are not Open Source programs. * * See http://www.opengroup.org/openmotif/license for full * details of the license agreement. Any use, reproduction, or * distribution of the program constitutes recipient's acceptance of * this agreement. * * EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS * PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY * WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY * OR FITNESS FOR A PARTICULAR PURPOSE * * EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT * NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE * EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. */ /* * (c) Copyright 1995 Digital Equipment Corporation. * (c) Copyright 1995 Hewlett-Packard Company. * (c) Copyright 1995 International Business Machines Corp. * (c) Copyright 1995 Sun Microsystems, Inc. * (c) Copyright 1995 Novell, Inc. * (c) Copyright 1995 FUJITSU LIMITED. * (c) Copyright 1995 Hitachi. */ /* * HISTORY */ /* * (c) Copyright 1989, 1990, 1991, 1992, 1993 OPEN SOFTWARE FOUNDATION, INC. * ALL RIGHTS RESERVED */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "GeoUtilsI.h" #include "GMUtilsI.h" #include "MessagesI.h" #include "RepTypeI.h" #include "ScreenI.h" #include "TravActI.h" #include "TraversalI.h" #include "XmI.h" #include static void ClassInitialize(void); static void ClassPartInitialize(WidgetClass classPart); static void Initialize(Widget req, Widget w, ArgList args, Cardinal *num_args); static void Destroy(Widget w); static void Resize(Widget w); static void Redisplay(Widget w, XEvent *event, Region region); static Boolean SetValues(Widget old, Widget req, Widget new_w, ArgList args, Cardinal *num_args); static XtGeometryResult QueryGeometry(Widget w, XtWidgetGeometry*req, XtWidgetGeometry*rep ); static XtGeometryResult GeometryManager(Widget w, XtWidgetGeometry *req, XtWidgetGeometry *rep); static void ChangeManaged(Widget w); static void InsertChild(Widget newChild); static void ConstraintInitialize(Widget req, Widget new_w, ArgList args, Cardinal *num_args); static void ConstraintDestroy(Widget w); static Boolean ConstraintSetValues(Widget old, Widget req, Widget new_w, ArgList args, Cardinal *num_args); static void SpinChildFocusChange(Widget focusWidget, XtPointer focusClient, XEvent *focusEvent, Boolean *focusContinue); static void SpinBArm(Widget armWidget, XEvent *armEvent, String *armParams, Cardinal *armCount ); static void SpinBDisarm(Widget disarmWidget, XEvent *disarmEvent, String *disarmParams, Cardinal *disarmCount); static void SpinBFirst(Widget firstWidget, XEvent *firstEvent, String *firstParams, Cardinal *firstCount ); static void SpinBLast(Widget lastWidget, XEvent *lastEvent, String *lastParams, Cardinal *lastCount ); static void SpinBLeft(Widget leftWidget, XEvent *leftEvent, String *leftParams, Cardinal *leftCount ); static void SpinBNext(Widget nextWidget, XEvent *nextEvent, String *nextParams, Cardinal *nextCount ); static void SpinBPrior(Widget priorWidget, XEvent *priorEvent, String *priorParams, Cardinal *priorCount ); static void SpinBRight(Widget rightWidget, XEvent *rightEvent, String *rightParams, Cardinal *rightCount ); static void SpinBEnter(Widget, XEvent*, String*, Cardinal*); static void SpinBLeave(Widget, XEvent*, String*, Cardinal*); static void ClearArrows(Widget clearW); static Boolean UpArrowSensitive(XmSpinBoxWidget spinW); static Boolean DownArrowSensitive(XmSpinBoxWidget spinW); static int NumericChildCount(XmSpinBoxWidget spinW); static Boolean WidgetIsChild(XmSpinBoxWidget spinW, Widget child); static Boolean ChildIsTraversable(Widget w); static int GetArrowDirection(Widget w, int spinDir); static void LayoutSpinBox(Widget w, XtWidgetGeometry *spinG, Widget child); static void NumToString(char **buffer, int min, int max, int decimal, int value ); static void DrawSpinArrow(Widget arrowWidget, int arrowFlag); static void SpinTimeOut(Widget w, int spinDelay); static void UpdateChildText(Widget textW); static Boolean ArrowWasHit(Widget arrowW, int arrowType, XEvent *arrowEvent); static void SpinBArrow(XtPointer spinData, XtIntervalId *spinInterval); static void SpinBAction(Widget actionWidget, short arrowHit ); static void FireCallbacks(XmSpinBoxCallbackStruct *spinBoxCallData, XtCallbackList callbackList, Widget arrowWidget, XEvent *arrowEvent, int arrowReason); static void ArrowCallback(Widget arrowWidget, XEvent *arrowEvent, int arrowReason); static Boolean ArrowVerify(Widget arrowWidget, XEvent *arrowEvent, int arrowReason ); static void ArrowSpinUp(Widget w, XEvent *callEvent); static void ArrowSpinDown(Widget w, XEvent *callEvent); static void GetSpinSize(Widget w, Dimension *wide, Dimension *high); static void SpinNChangeMoveCB(Widget nav, XtCallbackProc moveCB, XtPointer closure, Boolean setunset ); static void SpinNSetValue(Widget nav, XmNavigatorData nav_data, Boolean notify ); static void SpinNGetValue(Widget nav, XmNavigatorData nav_data ); static void GetPositionValue(Widget w, int offset, XtArgVal *value); static XmImportOperator SetPositionValue(Widget w, int offset, XtArgVal *value); static int GetMaximumPositionValue(XmSpinBoxConstraint sc); static int GetMinimumPositionValue(XmSpinBoxConstraint sc); static char * ValidatePositionValue(XmSpinBoxConstraint sc, int *position); static Boolean CvtStringToPositionValue(Display *dpy, XrmValue *args, Cardinal *num_args, XrmValue *from, XrmValue *to, XtPointer *converter_data); /* Macros */ #define SB_ArrowLayout(w) (((XmSpinBoxWidget) (w))->spinBox.arrow_layout) #define SB_ArrowsAreStacked(w) \ ((SB_ArrowLayout(w) == XmARROWS_END) || \ (SB_ArrowLayout(w) == XmARROWS_BEGINNING)) #define SB_NumArrowsWide(w) ((SB_ArrowsAreStacked(w)) ? 1 : 2) #define SB_NumArrowsHigh(w) ((SB_ArrowsAreStacked(w)) ? 2 : 1) #define SB_ShadowMargin 2 #define SB_ShadowPixels(w) \ ( (((XmSpinBoxWidget) (w))->manager.shadow_thickness) ? \ (((XmSpinBoxWidget) (w))->manager.shadow_thickness + SB_ShadowMargin) : \ 0 ) /* Actions table */ static XtActionsRec actionsTable [] = { {"SpinBArm", SpinBArm }, {"SpinBDisarm", SpinBDisarm }, {"SpinBPrior", SpinBPrior }, {"SpinBNext", SpinBNext }, {"SpinBLeft", SpinBLeft }, {"SpinBRight", SpinBRight }, {"SpinBFirst", SpinBFirst }, {"SpinBLast", SpinBLast }, {"SpinBEnter", SpinBEnter }, {"SpinBLeave", SpinBLeave }, }; #define BAD_SPIN_VALUES _XmMMsgSpinB_0003 #define BAD_SPIN_INCREMENT _XmMMsgSpinB_0004 #define BAD_SPIN_DIRECTION _XmMMsgSpinB_0005 #define BAD_SPIN_POSITION_MIN _XmMMsgSpinB_0006 #define BAD_SPIN_POSITION_MAX _XmMMsgSpinB_0007 #define BAD_SPIN_POSITION_TYPE _XmMMsgSpinB_0008 #define DEFAULT_ARROW_SIZE 16 #define defaultTranslations _XmSpinB_defaultTranslations static XtAccelerators spinAccel; /* Resources */ #define Offset(field) XtOffsetOf(XmSpinBoxRec,spinBox.field) static XtResource resources[] = { { XmNarrowLayout, XmCArrowLayout, XmRArrowLayout, sizeof(unsigned char), Offset(arrow_layout), XmRImmediate, (XtPointer) XmARROWS_END }, { XmNarrowOrientation, XmCArrowOrientation, XmRArrowOrientation, sizeof(unsigned char), Offset(arrow_orientation), XmRImmediate, (XtPointer) XmARROWS_VERTICAL }, { XmNarrowSize, XmCArrowSize, XmRHorizontalDimension, sizeof(Dimension), Offset(arrow_size), XmRImmediate, (XtPointer) DEFAULT_ARROW_SIZE }, { XmNmarginWidth, XmCMarginWidth, XmRHorizontalDimension, sizeof(Dimension), Offset(margin_width), XmRImmediate, (XtPointer) 2 }, { XmNmarginHeight, XmCMarginHeight, XmRVerticalDimension, sizeof(Dimension), Offset(margin_height), XmRImmediate, (XtPointer) 2 }, { XmNspacing, XmCSpacing, XmRHorizontalDimension, sizeof(Dimension), Offset(spacing), XmRImmediate, (XtPointer) 0 }, { XmNinitialDelay, XmCInitialDelay, XmRInt, sizeof(unsigned int), Offset(initial_delay), XmRImmediate, (XtPointer) 250 }, { XmNrepeatDelay, XmCRepeatDelay, XmRInt, sizeof(unsigned int), Offset(repeat_delay), XmRImmediate, (XtPointer) 200 }, { XmNdefaultArrowSensitivity, XmCDefaultArrowSensitivity, XmRArrowSensitivity, sizeof(unsigned char), Offset(default_arrow_sensitivity), XmRImmediate, (XtPointer) XmARROWS_SENSITIVE }, { XmNmodifyVerifyCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), Offset(modify_verify_cb), XmRPointer, NULL }, { XmNvalueChangedCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), Offset(value_changed_cb), XmRPointer, NULL, }, { XmNdetailShadowThickness, XmCShadowThickness, XmRHorizontalDimension, sizeof(Dimension), Offset(detail_shadow_thickness), XmRCallProc, (XtPointer) _XmSetThickness } }; /* Resources */ #define ConstraintOffset(field)\ XtOffsetOf(XmSpinBoxConstraintRec,spinBox.field) static XtResource constraints[] = { { XmNspinBoxChildType, XmCSpinBoxChildType, XmRSpinBoxChildType, sizeof(unsigned char), ConstraintOffset(sb_child_type), XmRImmediate, (XtPointer) XmSTRING }, { XmNpositionType, XmCPositionType, XmRPositionType, sizeof(unsigned char), ConstraintOffset(position_type), XmRImmediate, (XtPointer) XmPOSITION_VALUE }, { XmNnumValues, XmCNumValues, XmRInt, sizeof(int), ConstraintOffset(num_values), XmRImmediate, (XtPointer) 0 }, { XmNvalues, XmCValues, XmRXmStringTable, sizeof(XmStringTable), ConstraintOffset(values), XmRStringTable, NULL }, { XmNminimumValue, XmCMinimumValue, XmRInt, sizeof(int), ConstraintOffset(minimum_value), XmRImmediate, (XtPointer) 0 }, { XmNmaximumValue, XmCMaximumValue, XmRInt, sizeof(int), ConstraintOffset(maximum_value), XmRImmediate, (XtPointer) 10 }, { XmNincrementValue, XmCIncrementValue, XmRInt, sizeof(int), ConstraintOffset(increment_value), XmRImmediate, (XtPointer) 1 }, { XmNdecimalPoints, XmCDecimalPoints, XmRShort, sizeof(short), ConstraintOffset(decimal_points), XmRImmediate, (XtPointer) 0 }, { XmNarrowSensitivity, XmCArrowSensitivity, XmRArrowSensitivity, sizeof(unsigned char), ConstraintOffset(arrow_sensitivity), XmRImmediate, (XtPointer) XmARROWS_DEFAULT_SENSITIVITY }, { XmNwrap, XmCWrap, XmRBoolean, sizeof(Boolean), ConstraintOffset(wrap), XmRImmediate, (XtPointer) True }, { XmNposition, XmCPosition, XmRPositionValue, sizeof(int), ConstraintOffset(position), XmRImmediate, (XtPointer) 0 } }; static XmSyntheticResource syn_resources[] = { { XmNspacing, sizeof(Dimension), Offset(spacing), XmeFromHorizontalPixels, XmeToHorizontalPixels }, { XmNmarginHeight, sizeof(Dimension), Offset(margin_height), XmeFromVerticalPixels, XmeToVerticalPixels }, { XmNmarginWidth, sizeof(Dimension), Offset(margin_width), XmeFromHorizontalPixels, XmeToHorizontalPixels }, { XmNdetailShadowThickness, sizeof(Dimension), Offset(detail_shadow_thickness), XmeFromHorizontalPixels, XmeToHorizontalPixels } }; static XmSyntheticResource syn_constraints[] = { { XmNposition, sizeof(int), ConstraintOffset(position), GetPositionValue, SetPositionValue } }; static XmBaseClassExtRec spinBoxBaseClassExtRec = { NULL, NULLQUARK, XmBaseClassExtVersion, sizeof(XmBaseClassExtRec), NULL, /* InitializePrehook */ NULL, /* SetValuesPrehook */ NULL, /* InitializePosthook */ NULL, /* SetValuesPosthook */ NULL, /* secondaryObjectClass */ NULL, /* secondaryCreate */ NULL, /* getSecRes data */ { 0 }, /* fastSubclass flags */ NULL, /* getValuesPrehook */ NULL, /* getValuesPosthook */ NULL, /* ClassPartInitPrehook */ NULL, /* classPartInitPosthook*/ NULL, /* ext_resources */ NULL, /* compiled_ext_resources*/ 0, /* num_ext_resources */ FALSE, /* use_sub_resources */ XmInheritWidgetNavigable, /* widgetNavigable */ NULL /* focusChange */ }; /* The Spin class record definition */ externaldef (xmspinboxclassrec) XmSpinBoxClassRec xmSpinBoxClassRec= { { (WidgetClass)&xmManagerClassRec, /* superclass */ "XmSpinBox", /* class_name */ sizeof(XmSpinBoxRec), /* widget_size */ ClassInitialize, /* class_initialize */ ClassPartInitialize, /* class_part_initialize */ FALSE, /* class_inited */ Initialize, /* initialize */ NULL, /* initialize_hook */ XtInheritRealize, /* realize */ actionsTable, /* actions */ XtNumber(actionsTable), /* num_actions */ resources, /* resources */ XtNumber(resources), /* num_resources */ NULLQUARK, /* xrm_class */ TRUE, /* compress_motion */ XtExposeCompressMaximal | /* compress_exposure */ XtExposeNoRegion, TRUE, /* compress_enterleave */ FALSE, /* visible_interest */ Destroy, /* destroy */ Resize, /* resize */ Redisplay, /* expose */ SetValues, /* set_values */ NULL, /* set_values_hook */ XtInheritSetValuesAlmost, /* set_values_almost */ NULL, /* get_values_hook */ XtInheritAcceptFocus, /* accept_focus */ XtVersion, /* version */ NULL, /* callback private */ defaultTranslations, /* tm_table */ QueryGeometry, /* query_geometry */ NULL, /* display_accelerator */ (XtPointer)&spinBoxBaseClassExtRec, /* extension */ }, { /* composite_class fields */ GeometryManager, /* geometry_manager */ ChangeManaged, /* change_managed */ InsertChild, /* insert_child */ XtInheritDeleteChild, /* delete_child */ NULL, /* extension */ }, { /* constraint_class fields */ constraints, /* resource list */ XtNumber(constraints), /* num resources */ sizeof(XmSpinBoxConstraintRec), /* constraint size */ ConstraintInitialize, /* init proc */ ConstraintDestroy, /* destroy proc */ ConstraintSetValues, /* set values proc */ NULL, /* extension */ }, /* manager_class fields */ { NULL, /* translations */ syn_resources, /* syn_resources */ XtNumber(syn_resources), /* num_syn_resources */ syn_constraints, /* syn_cont_resources */ XtNumber(syn_constraints), /* num_syn_cont_resources */ NULL, /* parent_process */ NULL, /* extension */ }, /* spinbox_class fields */ { NULL, /* get_callback_widget */ NULL /* extension */ } }; externaldef(xmspinboxwidgetclass) WidgetClass xmSpinBoxWidgetClass = (WidgetClass)&xmSpinBoxClassRec; static XmConst XmNavigatorTraitRec spinBoxNT = { 0, SpinNChangeMoveCB, SpinNSetValue, SpinNGetValue, }; static XtConvertArgRec selfConvertArgs[] = { { XtBaseOffset, (XtPointer) 0, sizeof(int) } }; /****************************************************************************** ** *** METHODS ** *****************************************************************************/ static void ClassInitialize(void) { spinAccel = XtParseAcceleratorTable(_XmSpinB_defaultAccelerators); /* set up base class extension quark */ spinBoxBaseClassExtRec.record_type = XmQmotif; } static void ClassPartInitialize(WidgetClass classPart) { XmSpinBoxWidgetClass spinC; spinC = (XmSpinBoxWidgetClass) classPart; _XmFastSubclassInit(classPart, XmSPINBOX_BIT); /* Install the navigator trait for all subclasses */ XmeTraitSet((XtPointer)spinC, XmQTnavigator, (XtPointer) &spinBoxNT); XtSetTypeConverter( XmRString, XmRPositionValue, CvtStringToPositionValue, selfConvertArgs, XtNumber(selfConvertArgs), XtCacheNone, (XtDestructor) NULL) ; } /*ARGSUSED*/ static void Initialize(Widget req, /* unused */ Widget new_w, ArgList args, /* unused */ Cardinal *num_args) /* unused */ { XmSpinBoxWidget spinW = (XmSpinBoxWidget)new_w; XGCValues GCvalues; XtGCMask GCmask, unusedMask; spinW->spinBox.textw = 0; spinW->spinBox.dim_mask = 0; spinW->spinBox.last_hit = 0; spinW->spinBox.spin_timer = 0; spinW->spinBox.make_change = 0; spinW->spinBox.boundary = 0; spinW->spinBox.ideal_height = 0; spinW->spinBox.ideal_width = 0; spinW->spinBox.up_arrow_pressed = False; spinW->spinBox.down_arrow_pressed = False; spinW->spinBox.up_arrow_rect.x = 0; spinW->spinBox.up_arrow_rect.y = 0; spinW->spinBox.up_arrow_rect.width = 0; spinW->spinBox.up_arrow_rect.height = 0; spinW->spinBox.down_arrow_rect.x = 0; spinW->spinBox.down_arrow_rect.y = 0; spinW->spinBox.down_arrow_rect.width = 0; spinW->spinBox.down_arrow_rect.height = 0; if (!spinW->core.accelerators) spinW->core.accelerators = spinAccel; if (spinW->spinBox.initial_delay < 1) spinW->spinBox.initial_delay = spinW->spinBox.repeat_delay; /* Get arrow GC */ GCmask = GCForeground | GCBackground | GCGraphicsExposures; GCvalues.foreground = spinW->core.background_pixel; GCvalues.background = spinW->manager.foreground; GCvalues.graphics_exposures = False; /* Share gc with scrollbar */ spinW->spinBox.arrow_gc = XtAllocateGC(new_w, 0, GCmask, &GCvalues, 0, GCFont); GCmask |= GCFillStyle | GCStipple; unusedMask = GCClipXOrigin | GCClipYOrigin | GCFont; GCvalues.background = spinW->core.background_pixel; GCvalues.foreground = spinW->manager.foreground; GCvalues.fill_style = FillOpaqueStippled; GCvalues.stipple = _XmGetInsensitiveStippleBitmap(new_w); /* share GC with ArrowButton */ spinW->spinBox.insensitive_gc = XtAllocateGC(new_w, 0, GCmask, &GCvalues, GCClipMask, unusedMask); } static void Destroy(Widget w) { XmSpinBoxWidget spinW = (XmSpinBoxWidget)w; if (spinW->spinBox.arrow_gc != NULL) { XtReleaseGC(w, spinW->spinBox.arrow_gc); spinW->spinBox.arrow_gc = NULL; } if (spinW->spinBox.insensitive_gc != NULL) { XtReleaseGC(w, spinW->spinBox.insensitive_gc); spinW->spinBox.insensitive_gc = NULL; } } static void Resize(Widget w) { XtWidgetGeometry spinG; spinG.width = XtWidth(w); spinG.height = XtHeight(w); LayoutSpinBox(w, &spinG, NULL); if (XtIsRealized(w)) XClearArea(XtDisplay(w), XtWindow(w), 0, 0, 0, 0, True); /* Force Redisplay */ } /*ARGSUSED*/ static void Redisplay(Widget w, XEvent *event, /* unused */ Region region) /* unused */ { XmSpinBoxWidget spinW = (XmSpinBoxWidget) w; if (XtIsRealized(w)) { ClearArrows(w); if (spinW->manager.shadow_thickness > 0) { int width, height; width = (spinW->spinBox.ideal_width < XtWidth(spinW)) ? spinW->spinBox.ideal_width : XtWidth(spinW); height = (spinW->spinBox.ideal_height < XtHeight(spinW)) ? spinW->spinBox.ideal_height : XtHeight(spinW); XmeDrawShadows( XtDisplay(w), XtWindow(w), spinW->manager.top_shadow_GC, spinW->manager.bottom_shadow_GC, 0, 0, width, height, spinW->manager.shadow_thickness, XmSHADOW_OUT ); } _XmSetFocusFlag(w,XmFOCUS_IGNORE, False); DrawSpinArrow(w, XmARROW_UP); DrawSpinArrow(w, XmARROW_DOWN); } } /*ARGSUSED*/ static Boolean SetValues(Widget old, Widget req, Widget new_w, ArgList args, /* unused */ Cardinal *num_args ) /* unused */ { XtWidgetGeometry spinG; XmSpinBoxWidget oldW = (XmSpinBoxWidget)old; XmSpinBoxWidget reqW = (XmSpinBoxWidget)req; XmSpinBoxWidget newW = (XmSpinBoxWidget)new_w; Boolean displayFlag; displayFlag = False; /* Initial delay must be positive */ if (newW->spinBox.initial_delay < 1) newW->spinBox.initial_delay = newW->spinBox.repeat_delay; if ((newW->core.sensitive != oldW->core.sensitive) || (newW->core.ancestor_sensitive != oldW->core.ancestor_sensitive)) displayFlag = True; /* Check for geo changes, if realized */ if (XtIsRealized(new_w) && (reqW->spinBox.arrow_layout != oldW->spinBox.arrow_layout || reqW->spinBox.margin_width != oldW->spinBox.margin_width || reqW->spinBox.margin_height != oldW->spinBox.margin_height || reqW->spinBox.spacing != oldW->spinBox.spacing || reqW->spinBox.arrow_size != oldW->spinBox.arrow_size)) { spinG.width = 0; spinG.height = 0; GetSpinSize(new_w, &spinG.width, &spinG.height); XtWidth(new_w) = spinG.width; XtHeight(new_w) = spinG.height; if (XtIsRealized(old)) ClearArrows(old); LayoutSpinBox(new_w, &spinG, NULL); displayFlag = True; } if (reqW->spinBox.default_arrow_sensitivity != oldW->spinBox.default_arrow_sensitivity || reqW->spinBox.detail_shadow_thickness != oldW->spinBox.detail_shadow_thickness) displayFlag = True; return(displayFlag); } static XtGeometryResult QueryGeometry(Widget w, XtWidgetGeometry *req, XtWidgetGeometry *rep) { XmSpinBoxWidget spinW = (XmSpinBoxWidget)w; if (!XtIsRealized((Widget)spinW)) { rep->width = XtWidth(w); rep->height = XtHeight(w); } else { rep->width = 0; rep->height = 0; } GetSpinSize(w, &rep->width, &rep->height); return(XmeReplyToQueryGeometry(w, req, rep)); } /*ARGSUSED*/ static XtGeometryResult GeometryManager(Widget w, XtWidgetGeometry *req, XtWidgetGeometry *rep) /* unused */ { XtGeometryResult spinResult; XtWidgetGeometry spinG; XtWidgetGeometry origG; if (IsX(req)) if (w->core.x != req->x) return(XtGeometryNo); if (IsY(req)) if (w->core.y != req->y) return(XtGeometryNo); origG.width = w->core.width; origG.height = w->core.height; if (IsWidth(req)) w->core.width = req->width; if (IsHeight(req)) w->core.height = req->height; spinG.width = 0; spinG.height = 0; GetSpinSize(XtParent(w), &spinG.width, &spinG.height); spinG.request_mode = (CWWidth | CWHeight); spinResult = _XmMakeGeometryRequest(XtParent(w), &spinG); if (spinResult == XtGeometryYes) { LayoutSpinBox(XtParent(w), &spinG, w); /* Force Redisplay */ if (XtIsRealized(w)) XClearArea(XtDisplay(w), XtWindow(w), 0, 0, 0, 0, True); } else { w->core.width = origG.width; w->core.height = origG.height; spinResult = XtGeometryNo; } return(spinResult); } static void ChangeManaged(Widget w) { XtWidgetGeometry spinG; XmSpinBoxWidget spinW = (XmSpinBoxWidget) w; int i; if (XtIsRealized(w)) { spinG.width = 0; spinG.height = 0; } else { spinG.width = XtWidth(w); spinG.height = XtHeight(w); } GetSpinSize(w, &spinG.width, &spinG.height); spinG.request_mode = CWWidth | CWHeight; _XmMakeGeometryRequest(w, &spinG); LayoutSpinBox(w, &spinG, NULL); /* Update managed children */ /* Also make sure that focus is on the last created and managed * text/text_field child. If the last text/text_field child is not managed, * focus should be on the one previous to that. XmQTaccessTextual trait can * not be used to confirm the child to be text or text_field as this trait * is held by other widgets such as label as well. */ for (i = 0; i < SB_ChildCount(spinW); i++) { if (XtIsManaged(spinW->composite.children[i])) { if (XmIsTextField(spinW->composite.children[i]) || XmIsText(spinW->composite.children[i])) { spinW->spinBox.textw = spinW->composite.children[i]; } UpdateChildText(spinW->composite.children[i]); } } } static void InsertChild(Widget newChild) { XmSpinBoxWidget spinW = (XmSpinBoxWidget)XtParent(newChild); XtWidgetProc insert_child; /* call manager's InsertChild method */ _XmProcessLock(); insert_child = ((XmManagerWidgetClass)xmManagerWidgetClass) ->composite_class.insert_child; _XmProcessUnlock(); (*insert_child)(newChild); if (XmeTraitGet((XtPointer)XtClass(newChild), XmQTaccessTextual) != NULL) { spinW->spinBox.textw = newChild; XtInsertEventHandler( newChild, FocusChangeMask, False, SpinChildFocusChange, (XtPointer) spinW, XtListHead ); /* To handle implicit mode, we also call the focus change if a button is clicked. The work is finished in the event handler */ XtInsertEventHandler( newChild, ButtonPressMask, False, SpinChildFocusChange, (XtPointer) spinW, XtListHead ); } XtInstallAccelerators(newChild, (Widget)spinW); } /*ARGSUSED*/ static void ConstraintInitialize(Widget req, Widget new_w, ArgList args, /* unused */ Cardinal *num_args) /* unused */ { XmSpinBoxConstraint newC = SB_GetConstraintRec(new_w); XmSpinBoxConstraint reqC = SB_GetConstraintRec(req); XmSpinBoxWidget spinW; int valLoop; char *error = (char *) NULL; spinW = (XmSpinBoxWidget)XtParent(new_w); /* Numeric Child*/ if (SB_ChildIsNumeric(newC)) { /* enforce reasonable parameters */ if (newC->increment_value == 0) { XmeWarning(new_w, BAD_SPIN_INCREMENT); newC->increment_value = 1; } if ((newC->minimum_value < newC->maximum_value && newC->increment_value < 0) || (newC->minimum_value > newC->maximum_value && newC->increment_value > 0)) { XmeWarning(new_w, BAD_SPIN_DIRECTION); newC->increment_value *= -1; } } /* String Child*/ else { if (reqC->values != NULL) { /* buffer the values XmStringTable */ newC->values = (XmString *)XtMalloc(reqC->num_values * sizeof(XmString)); if (newC->values != NULL) for (valLoop = 0; valLoop < reqC->num_values; valLoop++) newC->values[valLoop] = XmStringCopy(reqC->values[valLoop]); } #if 0 /* * This is ifdef'ed out to be BC with DtSpinBox warning messages. */ if (newC->values == NULL || newC->num_values == 0) if (ChildIsTraversable(new_w)) if (XmeTraitGet((XtPointer)XtClass(new_w), XmQTaccessTextual) != NULL) XmeWarning(new_w, BAD_SPIN_VALUES); #endif } if (newC->position_type != XmPOSITION_VALUE && newC->position_type != XmPOSITION_INDEX) { newC->position_type = XmPOSITION_VALUE; XmeWarning(new_w, BAD_SPIN_POSITION_TYPE); } error = ValidatePositionValue(newC, &newC->position); if (error) XmeWarning(new_w, error); spinW->spinBox.up_arrow_pressed = False; spinW->spinBox.down_arrow_pressed = False; /* No reason to do the work until the child is managed */ if (XtIsManaged(new_w)) UpdateChildText(new_w); } static void ConstraintDestroy( Widget w ) { XmSpinBoxConstraint spinC = SB_GetConstraintRec(w); int itemLoop; /* give back the old values XmStringTable */ if (spinC->values != NULL) { for (itemLoop = 0; itemLoop < spinC->num_values; itemLoop++) XmStringFree(spinC->values[itemLoop]); XtFree((char*)spinC->values); spinC->values = NULL; spinC->num_values = 0; } } /*ARGSUSED*/ static Boolean ConstraintSetValues(Widget old, Widget req, Widget new_w, ArgList args, /* unused */ Cardinal *num_args ) /* unused */ { XmSpinBoxConstraint oldC = SB_GetConstraintRec(old); XmSpinBoxConstraint reqC = SB_GetConstraintRec(req); XmSpinBoxConstraint newC = SB_GetConstraintRec(new_w); XmSpinBoxWidget spinW = (XmSpinBoxWidget)XtParent(new_w); Boolean redisplayText = False; int nvi; int valLoop; char *error = (char *) NULL; /* * These resources have CG permissions only: * XmNspinBoxChildType XmNpositionType */ if (newC->position_type != oldC->position_type) { newC->position_type = oldC->position_type; XmeWarning(new_w, BAD_SPIN_POSITION_TYPE); } /* * BINARY COMPATIBILITY with DTSPINBOX * * However, DtSpinBox does not prevent setting XmNspinBoxChildType * so we have to allow it. * newC->sb_child_type = oldC->sb_child_type; */ if (newC->sb_child_type != oldC->sb_child_type) redisplayText = True; /**** Numeric Child ****/ if (SB_ChildIsNumeric(newC)) { /* enforce reasonable parameters */ if (newC->increment_value == 0) { XmeWarning(new_w, BAD_SPIN_INCREMENT); newC->increment_value = 1; } /* if something has changed ... */ if (newC->minimum_value != oldC->minimum_value || newC->maximum_value != oldC->maximum_value || newC->increment_value != oldC->increment_value || newC->decimal_points != oldC->decimal_points || newC->position != oldC->position) { redisplayText = True; /* force the step to go the right way */ if ((newC->minimum_value < newC->maximum_value && newC->increment_value < 0) || (newC->minimum_value > newC->maximum_value && newC->increment_value > 0)) { XmeWarning(new_w, BAD_SPIN_DIRECTION); newC->increment_value *= -1; } error = ValidatePositionValue(newC, &newC->position); if (error) XmeWarning(new_w, error); } } /**** String Child ****/ else if (ChildIsTraversable(new_w)) { /* buffer the new values XmStringTable */ if (reqC->values == NULL) reqC->values = oldC->values; else if (reqC->values != oldC->values) { newC->values = (XmString *)XtMalloc(reqC->num_values * sizeof(XmString)); if (newC->values != NULL) for (valLoop = 0; valLoop < reqC->num_values; valLoop++) newC->values[valLoop] = XmStringCopy(reqC->values[valLoop]); } error = ValidatePositionValue(newC, &newC->position); if (error) XmeWarning(new_w, error); #if 0 if (newC->values == NULL || newC->num_values == 0) if (XmeTraitGet((XtPointer)XtClass(new_w), XmQTaccessTextual) != NULL) XmeWarning(new_w, BAD_SPIN_VALUES); #endif if ((newC->position != oldC->position) || (newC->values != oldC->values) || (newC->num_values < oldC->num_values && newC->position > newC->num_values)) redisplayText = True; /* give back the old values XmStringTable */ if (reqC->values != oldC->values) { if (oldC->values != NULL) for (nvi = 0; nvi < oldC->num_values; nvi++) XmStringFree(oldC->values[nvi]); XtFree((char*)oldC->values); oldC->values = NULL; } } /* If the current focus child is the one requesting the change */ if (XtIsRealized((Widget)spinW) && spinW->spinBox.textw == new_w) { if (newC->arrow_sensitivity != oldC->arrow_sensitivity) { DrawSpinArrow((Widget) spinW, XmARROW_UP); DrawSpinArrow((Widget) spinW, XmARROW_DOWN); } } if (redisplayText) UpdateChildText(new_w); return(False); } /****************************************************************************** ** *** EVENT HANDLERS ** *****************************************************************************/ /****************************************************************************** * SpinChildFocusChange * Event Handler for Focus Change. *****************************************************************************/ /*ARGSUSED*/ static void SpinChildFocusChange(Widget focusWidget, XtPointer focusClient, XEvent *focusEvent, Boolean *focusContinue) /* unused */ { XmSpinBoxWidget spinW = (XmSpinBoxWidget)focusClient; if (_XmGetFocusPolicy((Widget) focusClient) == XmEXPLICIT) { if (focusEvent->type == FocusIn) { if (spinW->spinBox.textw != focusWidget) { spinW->spinBox.textw = focusWidget; } } } else { /* Only care if this is BSelect */ if (focusEvent->type == ButtonPress && focusEvent->xbutton.button == Button1) { if (spinW->spinBox.textw != (Widget) NULL) { Widget child = spinW->spinBox.textw; WidgetClass wc = XtClass(child); if (XmIsPrimitive(child)) { (*(((XmPrimitiveWidgetClass) wc) ->primitive_class.border_unhighlight))(child) ; } } spinW->spinBox.textw = focusWidget; if (spinW->spinBox.textw != (Widget) NULL) { Widget child = spinW->spinBox.textw; WidgetClass wc = XtClass(child); if (XmIsPrimitive(child)) { (*(((XmPrimitiveWidgetClass) wc) ->primitive_class.border_highlight))(child) ; } } } } if (focusWidget != (Widget) NULL) { DrawSpinArrow((Widget)focusClient, XmARROW_UP); DrawSpinArrow((Widget)focusClient, XmARROW_DOWN); } } /****************************************************************************** ** *** ACTIONS ** *****************************************************************************/ /***************************************************************************** * The Enter and Leave actions deal with implicit mode * (keyboardFocusPolicy == POINTER), where we need to indicate to the user * which child widget is to be updated on a mouse action. *****************************************************************************/ static void SpinBEnter(Widget widget, XEvent *event, String *params, Cardinal *num_params) { XmSpinBoxWidget spinW = (XmSpinBoxWidget)widget; Widget child = (Widget) spinW -> spinBox.textw; /* We only perform this action for POINTER mode */ if (_XmGetFocusPolicy(widget) != XmPOINTER) return; if (child != (Widget) NULL) { WidgetClass wc = XtClass(child); if (XmIsPrimitive(child)) { (*(((XmPrimitiveWidgetClass) wc) ->primitive_class.border_highlight))(child) ; } } } static void SpinBLeave(Widget widget, XEvent *event, String *params, Cardinal *num_params) { XmSpinBoxWidget spinW = (XmSpinBoxWidget)widget; Widget child = (Widget) spinW -> spinBox.textw; /* We only perform this action for POINTER mode */ if (_XmGetFocusPolicy(widget) != XmPOINTER) return; if (child != (Widget) NULL) { WidgetClass wc = XtClass(child); if (XmIsPrimitive(child)) { (*(((XmPrimitiveWidgetClass) wc) ->primitive_class.border_unhighlight))(child) ; } } } /****************************************************************************** * SpinBArm * Action for BSelect Down. *****************************************************************************/ /*ARGSUSED*/ static void SpinBArm(Widget armWidget, XEvent *armEvent, String *armParams, /* unused */ Cardinal *armCount) /* unused */ { if (armEvent->type == ButtonPress) if (ArrowWasHit(armWidget, XmARROW_UP, armEvent)) SpinBAction(armWidget, XmARROW_UP); else if (ArrowWasHit(armWidget, XmARROW_DOWN, armEvent)) SpinBAction(armWidget, XmARROW_DOWN); } /****************************************************************************** * SpinBDisarm * Action for BSelect Up. *****************************************************************************/ /*ARGSUSED*/ static void SpinBDisarm(Widget disarmWidget, XEvent *disarmEvent, String *disarmParams, /* unused */ Cardinal *disarmCount) /* unused */ { XmSpinBoxWidget spinW = (XmSpinBoxWidget)disarmWidget; if (spinW->spinBox.up_arrow_pressed || spinW->spinBox.down_arrow_pressed) { if (spinW->spinBox.initial_delay > 0 && spinW->spinBox.repeat_delay > 0) if (spinW->spinBox.spin_timer) XtRemoveTimeOut(spinW->spinBox.spin_timer); spinW->spinBox.up_arrow_pressed = False; spinW->spinBox.down_arrow_pressed = False; DrawSpinArrow(disarmWidget, XmARROW_UP); DrawSpinArrow(disarmWidget, XmARROW_DOWN); if (spinW->spinBox.make_change) { if (spinW->spinBox.last_hit == XmARROW_UP) ArrowSpinUp(disarmWidget, disarmEvent); else if (spinW->spinBox.last_hit == XmARROW_DOWN) ArrowSpinDown(disarmWidget, disarmEvent); } ArrowCallback(disarmWidget, disarmEvent, XmCR_OK); } spinW->spinBox.make_change = False; } /****************************************************************************** * SpinBFirst * Action for BeginData Key. *****************************************************************************/ /*ARGSUSED*/ static void SpinBFirst(Widget firstWidget, XEvent *firstEvent, String *firstParams, /* unused */ Cardinal *firstCount) /* unused */ { XmSpinBoxConstraint spinC; XmSpinBoxWidget spinW = (XmSpinBoxWidget)firstWidget; Widget child; int savePosition; child = XtWindowToWidget(XtDisplay(firstWidget), firstEvent->xany.window); child = spinW->spinBox.textw; if (WidgetIsChild(spinW, child) && DownArrowSensitive(spinW)) { spinW->spinBox.textw = child; spinC = SB_GetConstraintRec(child); savePosition = spinC->position; spinC->position = SB_ChildMinimumPositionValue(spinC); if (ArrowVerify((Widget)spinW, firstEvent, XmCR_SPIN_FIRST)) { UpdateChildText(spinW->spinBox.textw); ArrowCallback((Widget)spinW, firstEvent, XmCR_SPIN_FIRST); ArrowCallback((Widget)spinW, firstEvent, XmCR_OK); } else spinC->position = savePosition; } } /****************************************************************************** * SpinBLast * Action for EndOfData Key. *****************************************************************************/ /*ARGSUSED*/ static void SpinBLast(Widget lastWidget, XEvent *lastEvent, String *lastParams, /* unused */ Cardinal *lastCount) /* unused */ { XmSpinBoxConstraint spinC; XmSpinBoxWidget spinW = (XmSpinBoxWidget)lastWidget; Widget child; int savePosition; child = XtWindowToWidget(XtDisplay(lastWidget), lastEvent->xany.window); child = spinW->spinBox.textw; if (WidgetIsChild(spinW, child) && UpArrowSensitive(spinW)) { spinW->spinBox.textw = child; spinC = SB_GetConstraintRec(child); savePosition = spinC->position; spinC->position = SB_ChildMaximumPositionValue(spinC); if (ArrowVerify((Widget)spinW, lastEvent, XmCR_SPIN_LAST)) { UpdateChildText(spinW->spinBox.textw); ArrowCallback((Widget)spinW, lastEvent, XmCR_SPIN_LAST); ArrowCallback((Widget)spinW, lastEvent, XmCR_OK); } else spinC->position = savePosition; } } /****************************************************************************** * SpinBLeft * Action for Left Arrow. *****************************************************************************/ static void SpinBLeft(Widget leftWidget, XEvent *leftEvent, String *leftParams, Cardinal *leftCount) { XmSpinBoxWidget spinW = (XmSpinBoxWidget)leftWidget; if (LayoutIsRtoLM(spinW)) SpinBNext(leftWidget, leftEvent, leftParams, leftCount); else SpinBPrior(leftWidget, leftEvent, leftParams, leftCount); } /****************************************************************************** * SpinBNext * Action for DownArrow Key. *****************************************************************************/ /*ARGSUSED*/ static void SpinBNext(Widget nextWidget, XEvent *nextEvent, /* unused */ String *nextParams, /* unused */ Cardinal *nextCount) /* unused */ { SpinBAction(nextWidget, XmARROW_UP); } /****************************************************************************** * SpinBPrior * Action for UpArrow Key. *****************************************************************************/ /*ARGSUSED*/ static void SpinBPrior(Widget priorWidget, XEvent *priorEvent, /* unused */ String *priorParams, /* unused */ Cardinal *priorCount ) /* unused */ { SpinBAction(priorWidget, XmARROW_DOWN); } /****************************************************************************** * SpinBRight * Action for RightArrow Key. *****************************************************************************/ static void SpinBRight(Widget rightWidget, XEvent *rightEvent, String *rightParams, Cardinal *rightCount) { XmSpinBoxWidget spinW = (XmSpinBoxWidget)rightWidget; if (LayoutIsRtoLM(spinW)) SpinBPrior(rightWidget, rightEvent, rightParams, rightCount); else SpinBNext(rightWidget, rightEvent, rightParams, rightCount); } /****************************************************************************** ** *** OTHER FUNCTIONS ** *****************************************************************************/ /****************************************************************************** * ClearArrows * Erase Exisiting Arrows *****************************************************************************/ static void ClearArrows(Widget clearW) { XClearArea(XtDisplay(clearW), XtWindow(clearW), 0, 0, 0, 0, False); } /****************************************************************************** * UpArrowSensitive * Returns sensitive/insensitive for arrow. *****************************************************************************/ static Boolean UpArrowSensitive(XmSpinBoxWidget spinW) { XmSpinBoxConstraint spinC; unsigned char upState; if (XtIsSensitive((Widget) spinW) != True) upState = (unsigned char)XmARROWS_INSENSITIVE; else if (SB_ChildCount(spinW) && SB_WithChild(spinW)) { spinC = SB_GetConstraintRec(spinW->spinBox.textw); upState = spinC->arrow_sensitivity; } else upState = (unsigned char)XmARROWS_DEFAULT_SENSITIVITY; if (upState == (unsigned char)XmARROWS_DEFAULT_SENSITIVITY) upState = spinW->spinBox.default_arrow_sensitivity; return(upState & (unsigned char)XmARROWS_INCREMENT_SENSITIVE); } /****************************************************************************** * DownArrowSensitive * Returns sensitive/insensitive for arrow. *****************************************************************************/ static Boolean DownArrowSensitive(XmSpinBoxWidget spinW) { XmSpinBoxConstraint spinC; unsigned char downState; if (XtIsSensitive((Widget) spinW) != True) downState = (unsigned char)XmARROWS_INSENSITIVE; else if (SB_ChildCount(spinW) && SB_WithChild(spinW)) { spinC = SB_GetConstraintRec(spinW->spinBox.textw); downState = spinC->arrow_sensitivity; } else downState = (unsigned char)XmARROWS_DEFAULT_SENSITIVITY; if (downState == (unsigned char)XmARROWS_DEFAULT_SENSITIVITY) downState = spinW->spinBox.default_arrow_sensitivity; return(downState & (unsigned char)XmARROWS_DECREMENT_SENSITIVE); } /****************************************************************************** * NumericChildCount * Return Number of Numeric Children. *****************************************************************************/ static int NumericChildCount(XmSpinBoxWidget spinW) { XmSpinBoxConstraint spinC; int i; int childCount; childCount = 0; if (SB_WithChild(spinW)) for (i = 0; i < SB_ChildCount(spinW); i++) { spinC = SB_GetConstraintRec(spinW->composite.children[i]); if (SB_ChildIsNumeric(spinC)) childCount++; } return(childCount); } /****************************************************************************** * WidgetIsChild * Return True if Widget is SpinBox Child *****************************************************************************/ static Boolean WidgetIsChild(XmSpinBoxWidget spinW, Widget child) { Boolean childFlag; int i; childFlag = False; if (SB_WithChild(spinW)) for (i = 0; i < SB_ChildCount(spinW); i++) if (spinW->composite.children[i] == child) { childFlag = True; break; } return(childFlag); } /****************************************************************************** * ChildIsTraversable * Return True if XmNtraversalOn is set for child. *****************************************************************************/ static Boolean ChildIsTraversable(Widget w) { Boolean traverseFlag; Arg argList[2]; int n = 0; XtSetArg(argList[n], XmNtraversalOn, &traverseFlag); n++; XtGetValues(w, argList, n); return(traverseFlag); } /****************************************************************************** * GetArrowDirection * Returns the direction in which the arrow should be drawn * * widget - the spin box widget whose arrows are being drawn. * spinDir - the direction the arrow should cause the spinbox to spin. *****************************************************************************/ static int GetArrowDirection(Widget w, int spinDir) { int arrowDirection; int downDirection; int upDirection; int isRtoL; isRtoL = (int) LayoutIsRtoLM(w); if (SB_GetArrowOrientation(w) == (unsigned char) XmARROWS_VERTICAL) { upDirection = XmARROW_UP; downDirection = XmARROW_DOWN; } else { if (isRtoL) { upDirection = XmARROW_LEFT; downDirection = XmARROW_RIGHT; } else { upDirection = XmARROW_RIGHT; downDirection = XmARROW_LEFT; } } if (spinDir == XmARROW_UP) arrowDirection = upDirection; else arrowDirection = downDirection; return(arrowDirection); } /****************************************************************************** * LayoutSpinBox * Position Children and Arrows. * * The ideal layout of the children and arrows have the centerline of * the arrow layout running through the center of the median child * position. The median child position is roughly at the center of the * widget, modified by the baseline positions. * * Degradation behavior will first sacrifice the margins if the widget * isn't given enough room. Following this will be the spacing between * widgets, then finally the children will be shrunk (although the arrows * will not be). * * At beta, this code will use the approximation of the centerline * of the widget for the center of the child position and will not * perform the widget shrinking part of the graceful degradation of * layout. * * At final, this should be updated. *****************************************************************************/ typedef XmSpinBoxRec MySpinBoxRec; /*ARGSUSED*/ static void LayoutSpinBox(Widget w, XtWidgetGeometry *spinG, Widget child) /* unused */ { XmSpinBoxWidget spinW = (XmSpinBoxWidget) w; MySpinBoxRec *myW = (MySpinBoxRec *) w; int arrowLayout; int arrowSize; int i; int marginX, marginY; int numArrowsX, numArrowsY; int spacingX, spacingY; int posX, posY; int Xposition, Xmargin; /* May need to update this if stacked arrows are put back */ Position upX; Position downX; arrowLayout = (int) spinW->spinBox.arrow_layout; arrowSize = spinW->spinBox.arrow_size; /* * Figure the starting position of the arrows and children * in the X direction: * * 1. If there is enough room for our ideal width, then use the * .margin_width and .spacing resources to arrange the SpinBox. * 2. If not enough room, give up the .margin_width spacing. * 3. If still not enough room, shrink the spacing between * subwidgets. */ spacingX = spinW->spinBox.spacing; marginX = spinW->spinBox.margin_width + SB_ShadowPixels(spinW); numArrowsX = SB_NumArrowsWide(spinW); if (spinW->spinBox.ideal_width > spinG->width) { int requiredWidth = spinW->spinBox.ideal_width - (2 * spinW->spinBox.margin_width); marginX = 0; if (requiredWidth > spinG->width) { int spacesX = SB_ChildCount(spinW) + numArrowsX; int deltaX = requiredWidth - spinG->width; spacingX = ((spacesX * spinW->spinBox.spacing) - deltaX) / spacesX; if (spacingX < 0) spacingX = 0; } } /* * Figure the starting position of the arrows and children * in the Y direction. Use the same algorithm as for the * X direction with the following addition: * * 1a. If there is more room than required for our ideal width, * expand the margins 'til the arrows are centered vertically. */ spacingY = spinW->spinBox.spacing; numArrowsY = SB_NumArrowsHigh(spinW); if (spinW->spinBox.ideal_height > spinG->height) { int requiredHeight = spinW->spinBox.ideal_height - (2 * spinW->spinBox.margin_height); marginY = 0; if (requiredHeight > spinG->height) { int deltaY = requiredHeight - spinG->width; spacingY = ((numArrowsY * spinW->spinBox.spacing) - deltaY) / numArrowsY; if (spacingY < 0) spacingY = 0; } } else { int arrowsSpace = ((numArrowsY * arrowSize) + ((numArrowsY - 1) * spinW->spinBox.spacing)); marginY = (spinG->height - arrowsSpace) / 2; } /* * Get the starting position of the first SpinBox child in the X direction. */ posX = marginX; switch(arrowLayout) { case XmARROWS_BEGINNING: case XmARROWS_FLAT_BEGINNING: if (!LayoutIsRtoLM(w)) posX += (numArrowsX * (arrowSize + spacingX)); break; case XmARROWS_SPLIT: posX += ((numArrowsX / 2) * (arrowSize + spacingX)); break; case XmARROWS_END: case XmARROWS_FLAT_END: if (LayoutIsRtoLM(w)) posX += (numArrowsX * (arrowSize + spacingX)); break; default: break; } /* * Now position the managed children of the SpinBox. */ for (i = 0; i < SB_ChildCount(spinW); i++) { Widget childW = spinW->composite.children[i]; if (w != childW && XtIsManaged(childW)) { posY = (spinG->height - XtHeight(childW)) / 2; XmeConfigureObject(childW, posX, posY, ((Widget)childW)->core.width, ((Widget)childW)->core.height, ((Widget)childW)->core.border_width ); posX += XtWidth(childW) + spacingX; } } /* * Save the dimensions of the up and down arrows * for use by the arrow drawing procedure. */ spinW->spinBox.up_arrow_rect.width = spinW->spinBox.up_arrow_rect.height = spinW->spinBox.down_arrow_rect.width = spinW->spinBox.down_arrow_rect.height = arrowSize; /* * Save the X and Y positions of the up and down arrows * for use by the arrow drawing procedure. * NOTE: The window origin for X windows is the upper left-hand * corner. Therefore, the .up_arrow_rect.y gets the smaller * Y component. */ spinW->spinBox.up_arrow_rect.y = marginY; spinW->spinBox.down_arrow_rect.y = marginY + ((numArrowsY - 1) * (spacingY + arrowSize)); if (LayoutIsRtoLM(w)) { Xposition = marginX; Xmargin = posX; } else { Xposition = posX; Xmargin = marginX; } switch(arrowLayout) { case XmARROWS_BEGINNING: downX = upX = Xmargin; break; case XmARROWS_FLAT_BEGINNING: if(LayoutIsRtoLM(w)) { upX = Xmargin; downX = Xmargin + spacingX + arrowSize; } else { upX = Xmargin + spacingX + arrowSize; downX = Xmargin; } break; case XmARROWS_SPLIT: upX = Xposition; downX = Xmargin; break; case XmARROWS_END: downX = upX = Xposition; break; case XmARROWS_FLAT_END: if(LayoutIsRtoLM(w)) { upX = Xposition; downX = Xposition + spacingX + arrowSize; } else { upX = Xposition + spacingX + arrowSize; downX = Xposition; } break; default: break; } spinW->spinBox.up_arrow_rect.x = upX; spinW->spinBox.down_arrow_rect.x = downX; } /****************************************************************************** * NumToString * Convert Number to String to Be Displayed in Child *****************************************************************************/ /* ARGSUSED */ static void NumToString(char **buffer, int min, int max, int decimal, int value) { float result; int digits; int test; digits = 0; if (decimal < 1) decimal = 0; /* * BINARY COMPATIBILITY with DTSPINBOX * * This causes spaces to be insterted in the string passed back in * buffer. DtSpinBox does not do this so we have to alter the * behavior. * * test = MAX((int)abs(min), (int)abs(max)); */ if (value == 0) { digits = 1; if (decimal > 0) digits += decimal + 1; } else { test = abs(value); while (test > 0) { test = test / 10; digits++; } if (decimal > 0) digits = (digits <= decimal) ? decimal + 2 : digits + 1; if (value < 0) digits++; } test = decimal; result = (float)value; while (test > 0) { test--; result/=10.0; } *buffer = (char *)XtMalloc((digits + 1) * sizeof(char)); if (*buffer) { #ifdef __osf__ if (decimal == 0) sprintf(*buffer, "%*.0f", digits, result); else #endif sprintf(*buffer, "%*.*f", digits, decimal, result); } } /****************************************************************************** * DrawSpinArrow * Draw a Left or Right Arrow. *****************************************************************************/ static void DrawSpinArrow(Widget arrowWidget, int arrowFlag) { XmSpinBoxWidget spinW = (XmSpinBoxWidget)arrowWidget; Dimension arrowHeight; Dimension arrowWidth; Position arrowX; Position arrowY; Boolean arrowPressed; int arrowDirection; GC arrowGC; if (XtIsRealized((Widget)spinW)) { arrowPressed = False; if (arrowFlag == XmARROW_UP) { arrowX = spinW->spinBox.up_arrow_rect.x; arrowY = spinW->spinBox.up_arrow_rect.y; arrowWidth = spinW->spinBox.up_arrow_rect.width; arrowHeight = spinW->spinBox.up_arrow_rect.height; if (UpArrowSensitive(spinW)) { arrowGC = spinW->spinBox.arrow_gc; arrowPressed = spinW->spinBox.up_arrow_pressed; } else { arrowGC = spinW->spinBox.insensitive_gc; XSetClipMask(XtDisplay(arrowWidget), arrowGC, None); } } else { arrowX = spinW->spinBox.down_arrow_rect.x; arrowY = spinW->spinBox.down_arrow_rect.y; arrowWidth = spinW->spinBox.down_arrow_rect.width; arrowHeight = spinW->spinBox.down_arrow_rect.height; if (DownArrowSensitive(spinW)) { arrowGC = spinW->spinBox.arrow_gc; arrowPressed = spinW->spinBox.down_arrow_pressed; } else { arrowGC = spinW->spinBox.insensitive_gc; XSetClipMask(XtDisplay(arrowWidget), arrowGC, None); } } arrowWidth = (arrowWidth > 1) ? arrowWidth - 1 : 0; arrowHeight = (arrowHeight > 1) ? arrowHeight - 1 : 0; arrowDirection = GetArrowDirection(arrowWidget, arrowFlag); XmeDrawArrow( XtDisplay(arrowWidget), XtWindow(arrowWidget), arrowPressed ? spinW->manager.bottom_shadow_GC : spinW->manager.top_shadow_GC, arrowPressed ? spinW->manager.top_shadow_GC : spinW->manager.bottom_shadow_GC, arrowGC, arrowX, arrowY, arrowWidth, arrowHeight, spinW->spinBox.detail_shadow_thickness, arrowDirection ); } } /****************************************************************************** * SpinTimeOut * Add TimeOut for Spinning. *****************************************************************************/ static void SpinTimeOut(Widget w, int spinDelay) { XmSpinBoxWidget spinW = (XmSpinBoxWidget)w; if (spinW->spinBox.initial_delay > 0 && spinW->spinBox.repeat_delay > 0) spinW->spinBox.spin_timer = XtAppAddTimeOut( XtWidgetToApplicationContext(w), spinDelay, SpinBArrow, (XtPointer)w ); } /****************************************************************************** * UpdateChildText() * Updates the text widget with the current selection, by position. *****************************************************************************/ static void UpdateChildText(Widget textW) { XmAccessTextualTrait textT; XmSpinBoxConstraint textC; char *buffer = NULL; textT = (XmAccessTextualTrait) XmeTraitGet((XtPointer)XtClass(textW), XmQTaccessTextual); if (textT == NULL) return; if (textW) { textC = SB_GetConstraintRec(textW); if (SB_ChildIsNumeric(textC)) { NumToString(&buffer, textC->minimum_value, textC->maximum_value, textC->decimal_points, textC->position ); textT->setValue(textW, (XtPointer) buffer, XmFORMAT_MBYTE); if (buffer) XtFree(buffer); } else if (textC->values != NULL && textC->num_values) { textT->setValue(textW, (XtPointer) textC->values[textC->position], XmFORMAT_XmSTRING); } } } /****************************************************************************** * ArrowWasHit * Returns True if Pointer was Over Arrow When Bselect was Issued. *****************************************************************************/ static Boolean ArrowWasHit(Widget arrowW, int arrowType, XEvent *arrowEvent) { XmSpinBoxWidget spinW; XButtonEvent *hitEvent; XRectangle arrowArea; int arrowHit; int hitX; int hitY; arrowHit = False; if (arrowEvent->type == ButtonPress) { spinW = (XmSpinBoxWidget)arrowW; hitEvent = (XButtonEvent *)arrowEvent; if (arrowType == XmARROW_UP) arrowArea = spinW->spinBox.up_arrow_rect; else arrowArea = spinW->spinBox.down_arrow_rect; hitX = hitEvent->x - arrowArea.x; /* Normalize Event Position */ hitY = hitEvent->y - arrowArea.y; if (hitX < 0 || hitX > arrowArea.width || hitY < 0 || hitY > arrowArea.height) arrowHit = False; else arrowHit = True; } return(arrowHit); } /****************************************************************************** * SpinBArrow * Function Called by TimeOut. *****************************************************************************/ /*ARGSUSED*/ static void SpinBArrow(XtPointer spinData, XtIntervalId *spinInterval) /* unused */ { XmSpinBoxWidget spinW = (XmSpinBoxWidget)spinData; spinW->spinBox.make_change = False; if (spinW->spinBox.up_arrow_pressed) { if (UpArrowSensitive(spinW)) { SpinTimeOut((Widget) spinData, spinW->spinBox.repeat_delay); DrawSpinArrow((Widget) spinData, XmARROW_UP); ArrowSpinUp((Widget) spinData, (XEvent *) NULL); } else { spinW->spinBox.up_arrow_pressed = False; DrawSpinArrow((Widget) spinData, XmARROW_UP); } } else if (spinW->spinBox.down_arrow_pressed) { if (DownArrowSensitive(spinW)) { SpinTimeOut((Widget) spinData, spinW->spinBox.repeat_delay); DrawSpinArrow((Widget) spinData, XmARROW_DOWN); ArrowSpinDown((Widget) spinData, (XEvent *) NULL); } else { spinW->spinBox.down_arrow_pressed = False; DrawSpinArrow((Widget)spinData, XmARROW_DOWN); } } } /****************************************************************************** * SpinBAction * This Function Does the Work. *****************************************************************************/ static void SpinBAction(Widget actionWidget, short arrowHit) { XmSpinBoxWidget spinW = (XmSpinBoxWidget)actionWidget; Boolean upHit; Boolean downHit; upHit = (arrowHit == XmARROW_UP); downHit = (arrowHit == XmARROW_DOWN); if ((upHit && UpArrowSensitive(spinW)) || (downHit && DownArrowSensitive(spinW))) { spinW->spinBox.make_change = True; spinW->spinBox.last_hit = arrowHit; if (SB_ChildCount(spinW) && SB_WithChild(spinW)) XmProcessTraversal(spinW->spinBox.textw, XmTRAVERSE_CURRENT); if (upHit) { spinW->spinBox.up_arrow_pressed = True; DrawSpinArrow(actionWidget, XmARROW_UP); } else if (downHit) { spinW->spinBox.down_arrow_pressed = True; DrawSpinArrow(actionWidget, XmARROW_DOWN); } if (spinW->spinBox.initial_delay) SpinTimeOut(actionWidget, spinW->spinBox.initial_delay); } else spinW->spinBox.make_change = False; } /****************************************************************************** * FireCallbacks() * Setup Callback(s) for SpinBox. *****************************************************************************/ static void FireCallbacks(XmSpinBoxCallbackStruct *spinBoxCallData, XtCallbackList callbackList, Widget arrowWidget, XEvent *arrowEvent, int arrowReason) { XmSpinBoxConstraint spinC; XmSpinBoxWidget spinW; XmSpinBoxWidgetClass spinWC; XmString xmString = (XmString) NULL; spinW = (XmSpinBoxWidget) arrowWidget; spinWC = (XmSpinBoxWidgetClass) XtClass(arrowWidget); spinBoxCallData->reason = arrowReason; spinBoxCallData->event = arrowEvent; spinBoxCallData->widget = (spinWC->spinBox_class.get_callback_widget) ? (Widget) (*(spinWC->spinBox_class.get_callback_widget))((Widget)spinW) : (Widget) spinW->spinBox.textw; if (SB_ChildCount(spinW) && SB_WithChild(spinW)) { XtArgVal position; spinC = SB_GetConstraintRec(spinW->spinBox.textw); spinBoxCallData->doit = True; position = spinC->position; GetPositionValue( (Widget) spinW->spinBox.textw, XtOffset(XmSpinBoxConstraint, position), &position); spinBoxCallData->position = position; if (spinC->sb_child_type == XmSTRING) { if ((spinC->num_values > 0) && (spinC->position < spinC->num_values)) spinBoxCallData->value = spinC->values[spinC->position]; else spinBoxCallData->value = NULL; } else { char *buffer = (char *) NULL; NumToString(&buffer, spinC->minimum_value, spinC->maximum_value, spinC->decimal_points, spinC->position ); if (buffer) xmString = XmStringCreateLocalized(buffer); spinBoxCallData->value = xmString; if (buffer) XtFree(buffer); } if (arrowReason == XmCR_SPIN_NEXT || arrowReason == XmCR_SPIN_PRIOR) spinBoxCallData->crossed_boundary = spinW->spinBox.boundary; else spinBoxCallData->crossed_boundary = False; } else { spinBoxCallData->doit = False; spinBoxCallData->position = 0; spinBoxCallData->value = NULL; spinBoxCallData->crossed_boundary = False; } /* inform the application of the change */ XtCallCallbackList((Widget) spinW, callbackList, (XtPointer) spinBoxCallData); /* Clean up the temporary XmString created to hold the XmNUMERIC value. */ if (xmString != (XmString) NULL) XmStringFree(xmString); } /****************************************************************************** * ArrowCallback() * Setup and Call ValueChanged Callback(s) for SpinBox. *****************************************************************************/ static void ArrowCallback(Widget arrowWidget, XEvent *arrowEvent, int arrowReason) { XmSpinBoxWidget spinW = (XmSpinBoxWidget) arrowWidget; XmSpinBoxCallbackStruct spinBoxCallData; FireCallbacks(&spinBoxCallData, spinW->spinBox.value_changed_cb, arrowWidget, arrowEvent, arrowReason); } /****************************************************************************** * ArrowVerify() * Setup and Call ModifyVerify Callback(s) for SpinBox. *****************************************************************************/ static Boolean ArrowVerify(Widget arrowWidget, XEvent *arrowEvent, int arrowReason) { XmSpinBoxWidget spinW = (XmSpinBoxWidget) arrowWidget; XmSpinBoxCallbackStruct spinBoxCallData; FireCallbacks(&spinBoxCallData, spinW->spinBox.modify_verify_cb, arrowWidget, arrowEvent, arrowReason); if (SB_ChildCount(spinW) && SB_WithChild(spinW) && spinBoxCallData.doit) { char *error = (char *) NULL; XtArgVal position = spinBoxCallData.position; int int_pos; XmSpinBoxConstraint spinC = SB_GetConstraintRec(spinW->spinBox.textw); (void) SetPositionValue((Widget) spinW->spinBox.textw, XtOffset(XmSpinBoxConstraint, position), &position); int_pos = position; error = ValidatePositionValue(spinC, &int_pos); if (error) XmeWarning((Widget) spinW, error); spinC->position = int_pos; } return(spinBoxCallData.doit); } /****************************************************************************** * ArrowSpinUp() * Spin Increment Arrow. *****************************************************************************/ static void ArrowSpinUp(Widget w, XEvent *callEvent) { XmSpinBoxConstraint spinC; XmSpinBoxWidget spinW; int inPosition; spinW = (XmSpinBoxWidget)w; if (SB_ChildCount(spinW) && SB_WithChild(spinW)) { spinC = SB_GetConstraintRec(spinW->spinBox.textw); inPosition = spinC->position; spinW->spinBox.boundary = False; spinC->position += (SB_ChildIsNumeric(spinC) ? spinC->increment_value : 1); if (spinC->position > SB_ChildMaximumPositionValue(spinC)) { if (spinC->wrap) { spinW->spinBox.boundary = True; spinC->position = SB_ChildMinimumPositionValue(spinC); } else { spinC->position = inPosition; XBell(XtDisplay(spinW), 0); } } /* Update the Text Widget */ if (inPosition != spinC->position) if (ArrowVerify((Widget)spinW, callEvent, XmCR_SPIN_NEXT)) { UpdateChildText(spinW->spinBox.textw); ArrowCallback((Widget)spinW, callEvent, XmCR_SPIN_NEXT); } else spinC->position = inPosition; } else ArrowCallback((Widget)spinW, callEvent, XmCR_SPIN_NEXT); } /****************************************************************************** * ArrowSpinDown * Spin Decrement Arrow. *****************************************************************************/ static void ArrowSpinDown(Widget w, XEvent *callEvent) { XmSpinBoxConstraint spinC; XmSpinBoxWidget spinW; int inPosition; spinW = (XmSpinBoxWidget)w; if (SB_ChildCount(spinW) && SB_WithChild(spinW)) { spinC = SB_GetConstraintRec(spinW->spinBox.textw); inPosition = spinC->position; spinW->spinBox.boundary = False; spinC->position -= (SB_ChildIsNumeric(spinC) ? spinC->increment_value : 1); if (spinC->position < SB_ChildMinimumPositionValue(spinC)) { if (spinC->wrap) { spinW->spinBox.boundary = True; spinC->position = SB_ChildMaximumPositionValue(spinC); } else { spinC->position = inPosition; XBell(XtDisplay(spinW), 0); } } /* Update the Text Widget */ if (inPosition != spinC->position) if (ArrowVerify((Widget)spinW, callEvent, XmCR_SPIN_PRIOR)) { UpdateChildText(spinW->spinBox.textw); ArrowCallback((Widget)spinW, callEvent, XmCR_SPIN_PRIOR); } else spinC->position = inPosition; } else ArrowCallback((Widget)spinW, callEvent, XmCR_SPIN_PRIOR); } /***************************************************************************** * GetSpinSize *****************************************************************************/ static void GetSpinSize(Widget w, Dimension *wide, Dimension *high) { XmSpinBoxWidget spinW; Dimension childHeight; Dimension saveWide; Dimension saveHigh; Widget childW; int i; int arrowSize; int arrowsWide; int arrowsHigh; int spacing; spinW = (XmSpinBoxWidget)w; saveWide = XtWidth(spinW); saveHigh = XtHeight(spinW); XtWidth(spinW) = *wide; XtHeight(spinW) = *high; arrowSize = spinW->spinBox.arrow_size; arrowsWide = SB_NumArrowsWide(spinW); arrowsHigh = SB_NumArrowsHigh(spinW); spacing = spinW->spinBox.spacing; if (*wide == 0) { *wide = arrowsWide * arrowSize; *wide += (arrowsWide - 1) * spacing; *wide += 2 * spinW->spinBox.margin_width; *wide += 2 * SB_ShadowPixels(spinW); if (SB_WithChild(spinW)) for (i = 0; i < SB_ChildCount(spinW); i++) { childW = spinW->composite.children[i]; if (XtIsManaged(childW)) *wide += XtWidth(childW) + spinW->spinBox.spacing; } /* Remember our best width */ spinW->spinBox.ideal_width = *wide; } if (!*high) { *high = arrowsHigh * arrowSize; *high += (arrowsHigh - 1) * spacing; *high += 2 * spinW->spinBox.margin_height; if (SB_WithChild(spinW)) for (i = 0; i < SB_ChildCount(spinW); i++) { childW = spinW->composite.children[i]; if (XtIsManaged(childW)) { childHeight = XtHeight(childW); *high = MAX(*high, childHeight); } } /* Factor in the shadow thickness and remember our best size */ *high += 2 * SB_ShadowPixels(spinW); spinW->spinBox.ideal_height = *high; } if (*wide == 0) *wide = 1; if (*high == 0) *high = 1; XtWidth(spinW) = saveWide; XtHeight(spinW) = saveHigh; } /****************************************************************************** * SpinNChangeMoveCB * Navigator Trait Change/Move Callback. *****************************************************************************/ static void SpinNChangeMoveCB(Widget nav, XtCallbackProc moveCB, XtPointer closure, Boolean setunset) { if (setunset) XtAddCallback (nav, XmNvalueChangedCallback, moveCB, closure); else XtRemoveCallback (nav, XmNvalueChangedCallback, moveCB, closure); } /****************************************************************************** * SpinNSetValue * Navigator SetValue Function. *****************************************************************************/ static void SpinNSetValue(Widget nav, XmNavigatorData nav_data, Boolean notify) { XmSpinBoxConstraint spinC; XmSpinBoxWidget spinW = (XmSpinBoxWidget)nav; Arg arglist[6]; Cardinal argCount; int lastValue; int numericCount; int i; int minimum; int increment; Mask mask ; if (nav_data->valueMask & NavDimMask) spinW->spinBox.dim_mask = nav_data->dimMask ; if (!(numericCount = NumericChildCount(spinW))) return; if (!(spinW->spinBox.dim_mask & nav_data->dimMask)) return ; /* Spin box can be a 2d dimensional navigator at most. If there is only one dimension set, the following loop is only rnu once since the mask is update at the end of it */ mask = spinW->spinBox.dim_mask ; for (numericCount = 0, i = 0; i < SB_ChildCount(spinW) && numericCount < 2 && mask; i++) { spinC = SB_GetConstraintRec(spinW->composite.children[i]); if (SB_ChildIsNumeric(spinC)) { argCount = 0; numericCount++; lastValue = spinC->position; minimum=spinC->minimum_value; increment=spinC->increment_value; if ((nav_data->valueMask & NavMinimum) && (spinC->minimum_value != ACCESS_DIM(mask, nav_data->minimum))) { XtSetArg (arglist[argCount], XmNminimumValue, ACCESS_DIM(mask, nav_data->minimum)); minimum = ACCESS_DIM(mask, nav_data->minimum); argCount++; } if ((nav_data->valueMask & NavIncrement) && (spinC->increment_value != ACCESS_DIM(mask, nav_data->increment))) { XtSetArg (arglist[argCount], XmNincrementValue, ACCESS_DIM(mask, nav_data->increment)); increment = ACCESS_DIM(mask, nav_data->increment); argCount++; } /* Process value if different from current value or either increment or minimumValue changed (which will change the calculation */ if ((nav_data->valueMask & NavValue) && ((argCount != 0) || (lastValue != ACCESS_DIM(mask, nav_data->value)))) { XtArgVal position = ACCESS_DIM(mask, nav_data->value); GetPositionValue( (Widget) spinW->composite.children[i], XtOffset(XmSpinBoxConstraint, position), &position); XtSetArg (arglist[argCount], XmNposition, ((int)position)); argCount++; } if ((nav_data->valueMask & NavMaximum) && (spinC->maximum_value != ACCESS_DIM(mask, nav_data->maximum))) { XtSetArg (arglist[argCount], XmNmaximumValue, ACCESS_DIM(mask, nav_data->maximum) - 1); argCount++; } if (argCount) XtSetValues (spinW->composite.children[i], arglist, argCount); if (notify && ACCESS_DIM(mask, nav_data->value) != lastValue) ArrowCallback((Widget)spinW, NULL, XmCR_OK); /* mark the dimMask as x goes. So that if there is a second numeric child, it only gets y setting. If there was no X in the current mask, just stop here */ if (mask & NavigDimensionX) mask &= ~NavigDimensionX ; else mask = 0 ; } } } /****************************************************************************** * SpinNGetValue * Navigator GetValue Function. *****************************************************************************/ static void SpinNGetValue(Widget nav, XmNavigatorData nav_data) { XmSpinBoxConstraint spinC; XmSpinBoxWidget spinW; int i; int numericCount; Mask mask ; spinW = (XmSpinBoxWidget) nav; if (!(numericCount = NumericChildCount(spinW))) return; mask = nav_data->dimMask = spinW->spinBox.dim_mask; if (nav_data->valueMask & (NavValue|NavMinimum|NavMaximum|NavIncrement)) { /* get the value out of the numeric children, in order */ for (numericCount = 0, i = 0; i < SB_ChildCount(spinW) && numericCount < 2 && mask; i++) { spinC = SB_GetConstraintRec(spinW->composite.children[i]); if (SB_ChildIsNumeric(spinC)) { numericCount++; ASSIGN_DIM(mask, nav_data->value, spinC->position); ASSIGN_DIM(mask, nav_data->minimum, spinC->minimum_value); ASSIGN_DIM(mask, nav_data->maximum, spinC->maximum_value + 1); ASSIGN_DIM(mask, nav_data->increment, spinC->increment_value); mask &= ~NavigDimensionX ; } } } } /****************************************************************************** * GetPositionValue * XmExportProc conversion routine for converting between internal * and external representation for XmNposition resource. Internal * representation is always POSITION_VALUE. External representation * can be either POSITION_VALUE or POSITION_INDEX as determined * by XmNpositionType. *****************************************************************************/ static void GetPositionValue(Widget w, int offset, XtArgVal *value) { XmSpinBoxConstraint wc = SB_GetConstraintRec(w); if (SB_ChildIsNumeric(wc) && (!SB_ChildPositionTypeIsValue(wc))) *value = (*value - wc->minimum_value) / wc->increment_value; } /****************************************************************************** * SetPositionValue * XmImportProc conversion routine for converting between external * and internal representation for XmNposition resource. Internal * representation is always POSITION_VALUE. External representation * can be either POSITION_VALUE or POSITION_INDEX as determined * by XmNpositionType. *****************************************************************************/ static XmImportOperator SetPositionValue(Widget w, int offset, XtArgVal *value) { XmSpinBoxConstraint wc = SB_GetConstraintRec(w); if (SB_ChildIsNumeric(wc) && (!SB_ChildPositionTypeIsValue(wc))) *value = wc->minimum_value + (*value * wc->increment_value); return(XmSYNTHETIC_LOAD); } /****************************************************************************** * GetMaximumPositionValue * Returns the maximum allowable position for this widget. *****************************************************************************/ static int GetMaximumPositionValue(XmSpinBoxConstraint sc) { int max; if (sc == (XmSpinBoxConstraint) NULL) max = 0; else if (SB_ChildIsNumeric(sc)) max = sc->maximum_value; else max = (sc->num_values > 0) ? (sc->num_values - 1) : 0; return(max); } /****************************************************************************** * GetMinimumPositionValue * Returns the minimum allowable position for this widget. *****************************************************************************/ static int GetMinimumPositionValue(XmSpinBoxConstraint sc) { int min; if (sc == (XmSpinBoxConstraint) NULL) min = 0; else if (SB_ChildIsNumeric(sc)) min = sc->minimum_value; else min = 0; return(min); } /****************************************************************************** * ValidatePositionValue * Returns the minimum allowable position for this widget. *****************************************************************************/ static char * ValidatePositionValue(XmSpinBoxConstraint sc, int *position) { int val; char *err = (char *) NULL; val = SB_ChildMaximumPositionValue(sc); if (*position > val) { *position = val; err = BAD_SPIN_POSITION_MAX; } val = SB_ChildMinimumPositionValue(sc); if (*position < val) { *position = val; err = BAD_SPIN_POSITION_MIN; } return(err); } /*ARGSUSED*/ static Boolean CvtStringToPositionValue( Display *display, XrmValue *args, /* unused */ Cardinal *num_args, /* unused */ XrmValue *from, XrmValue *to, XtPointer *converter_data) /* unused */ { XtArgVal value; int offset = XtOffset(XmSpinBoxConstraint, position); Widget w = *((Widget *) args[0].addr); if (sscanf(from->addr, "%ld", (long*)&value) == 0) { XtDisplayStringConversionWarning(display, (char *)from->addr, XmRPositionValue); return False; } (void) SetPositionValue(w, offset, &value); _XM_CONVERTER_DONE( to, int, (int)value, ; ) } /* * * Public API * */ /************************************************************************ * XmCreateSpinBox * Create an instance of a Spin widget and return the widget id. ************************************************************************/ Widget XmCreateSpinBox(Widget parent, String name, ArgList arglist, Cardinal argcount) { return(XtCreateWidget(name, xmSpinBoxWidgetClass, parent, arglist, argcount)); } /************************************************************************ * XmSpinBoxValidatePosition * Validate the position value specified in string. ************************************************************************/ int XmSpinBoxValidatePosition(Widget text_field, int *position) { int i; float fPosition; int iPosition; int positionOffset = XtOffset(XmSpinBoxConstraint, position); String string; XmAccessTextualTrait textT; XmSpinBoxConstraint wc; XtAppContext app; if (text_field == (Widget) NULL) return(XmCURRENT_VALUE); app = XtWidgetToApplicationContext(text_field); _XmAppLock(app); textT = (XmAccessTextualTrait) XmeTraitGet((XtPointer) XtClass(text_field), XmQTaccessTextual); if (textT == NULL) { _XmAppUnlock(app); return(XmCURRENT_VALUE); } wc = SB_GetConstraintRec(text_field); if ((wc == (XmSpinBoxConstraint) NULL) || (! SB_ChildIsNumeric(wc))) { if ((wc) && (position)) *position = wc->position; _XmAppUnlock(app); return(XmCURRENT_VALUE); } string = textT->getValue(text_field, XmFORMAT_MBYTE); if (sscanf(string, "%f", &fPosition) == 0) { if (position) { XtArgVal external_position = wc->position; GetPositionValue(text_field, positionOffset, &external_position); *position = (int)external_position; } _XmAppUnlock(app); return(XmCURRENT_VALUE); } XtFree(string); for (i=0; idecimal_points; i++) fPosition *= 10.0; iPosition = (int) fPosition; if (iPosition < SB_ChildMinimumPositionValue(wc)) { if (position) { XtArgVal external_position = SB_ChildMinimumPositionValue(wc); GetPositionValue(text_field, positionOffset, &external_position); *position = (int)external_position; } _XmAppUnlock(app); return(XmMINIMUM_VALUE); } if (iPosition > SB_ChildMaximumPositionValue(wc)) { if (position) { XtArgVal external_position = SB_ChildMaximumPositionValue(wc); GetPositionValue(text_field, positionOffset, &external_position); *position = (int)external_position; } _XmAppUnlock(app); return(XmMAXIMUM_VALUE); } if ((iPosition % wc->increment_value) != 0) { int iValue = wc->increment_value; if (position) { XtArgVal external_position = (iPosition / iValue) * iValue; GetPositionValue(text_field, positionOffset, &external_position); *position = (int)external_position; } _XmAppUnlock(app); return(XmINCREMENT_VALUE); } if (position) { XtArgVal external_position = iPosition; GetPositionValue(text_field, positionOffset, &external_position); *position = (int)external_position; } _XmAppUnlock(app); return(XmVALID_VALUE); }