libDtSvc: Change to ANSI function definitions
[oweals/cde.git] / cde / lib / DtWidget / SpinBox.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: SpinBox.c /main/9 1996/10/29 12:49:58 cde-hp $
24  *
25  * (c) Copyright 1996 Digital Equipment Corporation.
26  * (c) Copyright 1993,1994,1996 Hewlett-Packard Company.
27  * (c) Copyright 1993,1994,1996 International Business Machines Corp.
28  * (c) Copyright 1993,1994,1996 Sun Microsystems, Inc.
29  * (c) Copyright 1993,1994,1996 Novell, Inc. 
30  * (c) Copyright 1996 FUJITSU LIMITED.
31  * (c) Copyright 1996 Hitachi.
32  */
33
34 /***********************************************************
35 Copyright 1993 Interleaf, Inc.
36
37 Permission to use, copy, modify, and distribute this software
38 and its documentation for any purpose without fee is granted,
39 provided that the above copyright notice appear in all copies
40 and that both copyright notice and this permission notice appear
41 in supporting documentation, and that the name of Interleaf not
42 be used in advertising or publicly pertaining to distribution of
43 the software without specific written prior permission.
44
45 Interleaf makes no representation about the suitability of this
46 software for any purpose. It is provided "AS IS" without any
47 express or implied warranty. 
48 ******************************************************************/
49
50 /*
51  * (C) Copyright 1991,1992, 1993
52  * Interleaf, Inc.
53  * 9 Hillside Avenue, 
54  * Waltham, MA  02154
55  *
56  * SpinBox.c (DtSpinBoxWidget):
57  *
58  * I wanted a margin around the widget (outside the shadow, like buttons), 
59  * so that the spin_box could be made the smae size as a 
60  * push-button, etc.  The bulletin-board widget always puts the shadow at 
61  * the outside edge of the widget, so spin_box is a sublcass of
62  * manager, and we do everything ourselves.
63  * 
64  * One must be carefull when using Dimension (for core width and height).
65  * Dimension is an unsigned short.  This causes problems when subtracting
66  * and ending up with what should be a negative number (but it doesn't).
67  * All child widget positioning is done by the spin_box.  We don't
68  * use any heavy-weight forms, etc. to help us out.
69  * 
70  * There is no padding when editable.  If using a label, give it a
71  * small margin, so it doesn't run up against the side of our
72  * shadow or the arrow.
73  *
74  * Make some of the SpinBox functions common, so they can be shared
75  * with ComboBox.
76  *
77  * Known bugs:
78  *          Changing margin_width or margin_height resources when the
79  *          spin_box has focus will probably result in display glitches.
80  */
81 /*
82  * The DtSpinBox widget is rigged with the Motif widget binary compatibilit
83  * mechanism. All Motif-specific changes for this mechanism are preceded
84  * by a comment including the string "MotifBc".
85  *
86  * For a description of the Motif widget binary compatibility mechanism
87  * see the reference manual entry on XmResolveAllPartOffsets().
88  *
89  */
90
91 /*Support for a legacy operating system has resulted in some leftover cruft
92  * code which wasn't ifdefed out, this needs to be cleaned, such code is
93  * marked Legacy: - 05/19/18 - C
94  */
95
96 #include <Dt/DtMsgsP.h>
97 #include <Xm/DrawP.h>
98 #include <Xm/XmP.h>
99 #include <Xm/RepType.h>
100 #include "SpinBoxP.h"
101 #include "DtWidgetI.h"
102
103 #include <Xm/XmPrivate.h>    /* _XmShellIsExclusive */
104
105 #ifdef I18N_MSG
106 #include <langinfo.h>
107 #endif 
108
109
110 /*
111  * MotifBc
112  */
113 #define DtSpinBoxIndex (XmManagerIndex + 1)
114 static XmOffsetPtr ipot; /* Instance part offset table */
115 static XmOffsetPtr cpot; /* Constraint part offset table */
116
117 static void     ClassInitialize ();
118 static void     Initialize (DtSpinBoxWidget request, 
119                                DtSpinBoxWidget new, ArgList given_args, 
120                                Cardinal *num_args);
121 static XmNavigability WidgetNavigable (DtSpinBoxWidget spin);
122 static void     _SpinBoxFocusIn (DtSpinBoxWidget spin, XEvent *event, 
123                                        char **params, Cardinal *num_params);
124 static void     _SpinBoxFocusOut (DtSpinBoxWidget spin, XEvent *event,
125                                         char **params, Cardinal *num_params);
126 static void     DrawHighlight (DtSpinBoxWidget spin, Boolean clear);
127 static void     _SpinBoxUp (DtSpinBoxWidget spin, 
128                                   XEvent *event, char **params, 
129                                   Cardinal *num_params);
130 static void     _SpinBoxDown (DtSpinBoxWidget spin, 
131                                     XEvent *event, char **params, 
132                                     Cardinal *num_params);
133 static void     _SpinBoxLeft (DtSpinBoxWidget spin, 
134                                     XEvent *event, char **params, 
135                                     Cardinal *num_params);
136 static void     _SpinBoxRight (DtSpinBoxWidget spin, 
137                                      XEvent *event, char **params, 
138                                      Cardinal *num_params);
139 static void     _SpinBoxBeginLine (DtSpinBoxWidget spin, 
140                                          XEvent *event, char **params, 
141                                          Cardinal *num_params);
142 static void     _SpinBoxEndLine (DtSpinBoxWidget spin, 
143                                        XEvent *event, char **params, 
144                                        Cardinal *num_params);
145 static void     _SpinBoxGetFocus (DtSpinBoxWidget spin,
146                                        XEvent *event, char **params,
147                                        Cardinal *num_params);
148 static void     _SpinBoxPrevTabGroup (DtSpinBoxWidget spin,
149                                        XEvent *event, char **params,
150                                        Cardinal *num_params);
151 static void     _SpinBoxNextTabGroup (DtSpinBoxWidget spin,
152                                        XEvent *event, char **params,
153                                        Cardinal *num_params);
154
155 static void     CheckResources (DtSpinBoxWidget spin);
156 static void     Destroy (DtSpinBoxWidget spin);
157 static void     Resize (DtSpinBoxWidget spin);
158 static void     Redisplay (DtSpinBoxWidget w, XEvent *event, 
159                               Region region);
160 static XtGeometryResult GeometryManager (Widget w, 
161                                             XtWidgetGeometry *request, 
162                                             XtWidgetGeometry *reply);
163 static void     SetSpinBoxSize (DtSpinBoxWidget spin);
164 static void     ForceChildSizes (DtSpinBoxWidget spin);
165 static void     CalculateSizes (DtSpinBoxWidget spin,
166                                 Dimension *pwidth,
167                                 Dimension *pheight,
168                                 Dimension *parrow_width);
169 static void     LayoutChildren (DtSpinBoxWidget spin);
170 static Boolean  SetValues (DtSpinBoxWidget current, 
171                               DtSpinBoxWidget request, 
172                               DtSpinBoxWidget new);
173 static void     ClearShadow (DtSpinBoxWidget w, Boolean all);
174 static void     DrawShadow (DtSpinBoxWidget w);
175 static void     StoreResourceInfo (DtSpinBoxPart *spin_p,
176                                       DtSpinBoxPart *old_p,
177                                       Boolean do_items);
178 static char*    GetTextString (XmString xm_string);
179 static void     SetTextFieldData (DtSpinBoxWidget spin);
180 static void     SetMaximumLabelSize (DtSpinBoxPart *spin_p);
181 static void     SetLabelData (DtSpinBoxWidget spin);
182 static void     timer_dispatch (XtPointer client_data, XtIntervalId *id);
183 static void     TextFieldActivate (DtSpinBoxPart *spin_p);
184 static Boolean  SendCallback (DtSpinBoxWidget spin, XEvent *event,
185                                  Boolean value_changed, int position,
186                                  float current, Boolean crossed);
187 static void     FinishUpDown (DtSpinBoxWidget spin, 
188                                  XtPointer arrow_call_data, int new_position,
189                                  float new_current, Boolean crossed);
190 static void     up_cb (Widget w, XtPointer client_data, 
191                           XtPointer call_data);
192 static void     down_cb (Widget w, XtPointer client_data, 
193                             XtPointer call_data);
194 static void     disarm_cb (Widget w, XtPointer client_data, 
195                               XtPointer call_data);
196 static void     grab_leave_cb (Widget w, XtPointer client_data, 
197                                   XEvent *event, Boolean *dispatch);
198 static void     text_losing_focus_cb (Widget w, XtPointer client_data,
199                                          XtPointer call_data);
200 static void     text_activate_cb (Widget w, XtPointer client_data,
201                                      XtPointer call_data);
202 static void     text_focus_cb (Widget w, XtPointer client_data,
203                                   XtPointer call_data);
204 static XmImportOperator _XmSetSyntheticResForChild (Widget widget,
205                                                        int offset, 
206                                                        XtArgVal * value);
207
208 static XmString InitLabel = NULL;
209
210 /*
211  * MotifBc
212  */
213 #define Label(w) XmField(w,ipot,DtSpinBox,label,Widget)
214 #define UpArrow(w) XmField(w,ipot,DtSpinBox,up_arrow,Widget)
215 #define DownArrow(w) XmField(w,ipot,DtSpinBox,down_arrow,Widget)
216 #define WhichArrow(w) XmField(w,ipot,DtSpinBox,which_arrow,unsigned char)
217 #define InitCb(w) XmField(w,ipot,DtSpinBox,init_cb,Boolean)
218 #define Grabbed(w) XmField(w,ipot,DtSpinBox,grabbed,Boolean)
219 #define Base(w) XmField(w,ipot,DtSpinBox,base,int)
220 #define Min(w) XmField(w,ipot,DtSpinBox,min,float)
221 #define Max(w) XmField(w,ipot,DtSpinBox,max,float)
222 #define Increment(w) XmField(w,ipot,DtSpinBox,increment,float)
223 #define Current(w) XmField(w,ipot,DtSpinBox,current,float)
224 #define FloatFormat(w) (String) &(XmField(w,ipot,DtSpinBox,float_format,char *))
225 #define OldWidth(w) XmField(w,ipot,DtSpinBox,old_width,Dimension)
226 #define OldHeight(w) XmField(w,ipot,DtSpinBox,old_height,Dimension)
227 #define LabelMaxLength(w) XmField(w,ipot,DtSpinBox,label_max_length,Dimension)
228 #define LabelMaxHeight(w) XmField(w,ipot,DtSpinBox,label_max_height,Dimension)
229
230 #define ArrowSensitivity(w) XmField(w,ipot,DtSpinBox,arrow_sensitivity,unsigned char)
231 #define DecimalPoints(w) XmField(w,ipot,DtSpinBox,decimal_points,short)
232 #define NumericIncrement(w) XmField(w,ipot,DtSpinBox,numeric_increment,int)
233 #define Maximum(w) XmField(w,ipot,DtSpinBox,maximum,int)
234 #define Minimum(w) XmField(w,ipot,DtSpinBox,minimum,int)
235 #define ItemCount(w) XmField(w,ipot,DtSpinBox,item_count,int)
236 #define Position(w) XmField(w,ipot,DtSpinBox,position,int)
237 #define ChildType(w) XmField(w,ipot,DtSpinBox,child_type,unsigned char)
238 #define Items(w) XmField(w,ipot,DtSpinBox,items,XmStringTable)
239 #define ActivateCallback(w) XmField(w,ipot,DtSpinBox,activate_callback,XtCallbackList)
240 #define Alignment(w) XmField(w,ipot,DtSpinBox,alignment,unsigned char)
241 #define ArrowLayout(w) XmField(w,ipot,DtSpinBox,arrow_layout,unsigned char)
242 #define ArrowSize(w) XmField(w,ipot,DtSpinBox,arrow_size,Dimension)
243 #define TextColumns(w) XmField(w,ipot,DtSpinBox,text_columns,short)
244 #define Editable(w) XmField(w,ipot,DtSpinBox,editable,Boolean)
245 #define FocusCallback(w) XmField(w,ipot,DtSpinBox,focus_callback,XtCallbackList)
246 #define InitialDelay(w) XmField(w,ipot,DtSpinBox,initial_delay,unsigned int)
247 #define LosingFocusCallback(w) XmField(w,ipot,DtSpinBox,losing_focus_callback,XtCallbackList)
248 #define MarginHeight(w) XmField(w,ipot,DtSpinBox,margin_height,Dimension)
249 #define MarginWidth(w) XmField(w,ipot,DtSpinBox,margin_width,Dimension)
250 #define TextMaxLength(w) XmField(w,ipot,DtSpinBox,text_max_length,int)
251 #define ModifyVerifyCallback(w) XmField(w,ipot,DtSpinBox,modify_verify_callback,XtCallbackList)
252 #define RecomputeSize(w) XmField(w,ipot,DtSpinBox,recompute_size,Boolean)
253 #define RepeatDelay(w) XmField(w,ipot,DtSpinBox,repeat_delay,unsigned int)
254 #define Text(w) XmField(w,ipot,DtSpinBox,text,Widget)
255 #define ValueChangedCallback(w) XmField(w,ipot,DtSpinBox,value_changed_callback,XtCallbackList)
256 #define Wrap(w) XmField(w,ipot,DtSpinBox,wrap,Boolean)
257 #define Timer(w) XmField(w,ipot,DtSpinBox,timer,XtIntervalId)
258
259 /* SpinBox and Superclass resource macros*/
260 #define PUnitType(w)        w->primitive.unit_type
261 #define MUnitType(w)        w->manager.unit_type
262 #define MFgPixel(w)         w->manager.foreground
263 #define SPIN_SHADOW(w)      w->manager.shadow_thickness
264 #define CBgPixel(w)         w->core.background_pixel
265 #define CBgPixmap(w)        w->core.background_pixmap
266 #define Width(w)            w->core.width
267 #define Height(w)           w->core.height
268 #define SPIN_MARGIN_W(w)    MarginWidth(w)
269 #define SPIN_MARGIN_H(w)    MarginHeight(w)
270 #define MAXINT 2147483647  /* Taken from TextF.c */
271 #define DEFAULT_COL 20
272
273 /* Legacy: Label get Focus */
274 static XtTranslations child_trans_label;
275 /* Legacy: Keyboard only for Text */
276 static XtTranslations child_trans_text;
277
278 static XtTranslations child_trans_arrow;
279
280 static XtTranslations child_trans;
281 static XtTranslations spin_trans;
282
283
284 static char const SpinBoxTranslationTable[] = "\
285         <FocusIn>:              SpinBoxFocusIn() \n\
286         <FocusOut>:             SpinBoxFocusOut() \n\
287         <Key>osfUp:             SpinBoxUp() \n\
288         <Key>osfDown:           SpinBoxDown() \n\
289         <Key>osfRight:          SpinBoxRight() \n\
290         <Key>osfLeft:           SpinBoxLeft() \n\
291         <Key>osfBeginLine:      SpinBoxBeginLine() \n\
292         <Key>osfEndLine:        SpinBoxEndLine() \n\
293 ";
294
295 static char const SpinBoxChildTranslationTable[] = "\
296         <Key>osfUp:             SpinBoxUp(child) \n\
297         <Key>osfDown:           SpinBoxDown(child) \n\
298         <Key>osfRight:          SpinBoxRight(child) \n\
299         <Key>osfLeft:           SpinBoxLeft(child) \n\
300         <Key>osfBeginLine:      SpinBoxBeginLine(child) \n\
301         <Key>osfEndLine:        SpinBoxEndLine(child) \n\
302 ";
303
304 /* #5: Label get focus */
305 static char const SpinBoxLabelTranslationTable[] = "\
306         <Key>osfUp:             SpinBoxUp(child) \n\
307         <Key>osfDown:           SpinBoxDown(child) \n\
308         <Key>osfRight:          SpinBoxRight(child) \n\
309         <Key>osfLeft:           SpinBoxLeft(child) \n\
310         <Key>osfBeginLine:      SpinBoxBeginLine(child) \n\
311         <Key>osfEndLine:        SpinBoxEndLine(child) \n\
312         <Key>osfDown:        SpinBoxGetFocus() \n\
313         <Btn1Down>,<Btn1Up>:  SpinBoxGetFocus() \n\
314         <Key>osfSelect:       SpinBoxGetFocus() \n\
315         ~s ~m ~a <Key>space:  SpinBoxGetFocus() \n\
316 ";
317
318 /* Legacy: Keyboard Only Traversing During Editable-Mode */
319 static char const SpinBoxTextTranslationTable[] = "\
320         <Key>osfUp:             SpinBoxUp(child) SpinBoxRight(child)\n\
321         <Key>osfDown:           SpinBoxDown(child) SpinBoxLeft(child)\n\
322 ";
323 static char const SpinBoxArrowTranslationTable[] = "\
324         <Key>osfUp:             SpinBoxUp(child) \n\
325         <Key>osfDown:           SpinBoxDown(child) \n\
326         <Key>osfRight:          SpinBoxRight(child) \n\
327         <Key>osfLeft:           SpinBoxLeft(child) \n\
328         <Key>osfBeginLine:      SpinBoxBeginLine(child) \n\
329         <Key>osfEndLine:        SpinBoxEndLine(child) \n\
330         s ~m ~a <Key>Tab:    SpinBoxPrevTabGroup()\n\
331         ~m ~a <Key>Tab:      SpinBoxNextTabGroup()\n\
332 ";
333
334
335 static XtActionsRec SpinBoxActionTable[] = {
336        {"SpinBoxFocusIn",       (XtActionProc)_SpinBoxFocusIn},
337        {"SpinBoxFocusOut",      (XtActionProc)_SpinBoxFocusOut},
338        {"SpinBoxUp",            (XtActionProc)_SpinBoxUp},
339        {"SpinBoxDown",  (XtActionProc)_SpinBoxDown},
340        {"SpinBoxRight", (XtActionProc)_SpinBoxRight},
341        {"SpinBoxLeft",  (XtActionProc)_SpinBoxLeft},
342        {"SpinBoxBeginLine",     (XtActionProc)_SpinBoxBeginLine},
343        {"SpinBoxEndLine",       (XtActionProc)_SpinBoxEndLine},
344        {"SpinBoxGetFocus",      (XtActionProc)_SpinBoxGetFocus},
345        {"SpinBoxPrevTabGroup",   (XtActionProc)_SpinBoxPrevTabGroup},
346        {"SpinBoxNextTabGroup",   (XtActionProc)_SpinBoxNextTabGroup},
347 };
348
349 /* DtSpinBoxWidget resources */
350 /* MotifBc */
351 #define offset(field) XtOffset(DtSpinBoxWidget, field)
352 #define DtOffset(field) XmPartOffset(DtSpinBox,field)
353 static XmPartResource resources[] = {
354     {XmNshadowThickness, XmCShadowThickness, XmRHorizontalDimension, 
355          sizeof(Dimension), offset(manager.shadow_thickness),
356          XmRImmediate, (XtPointer)TEXT_FIELD_SHADOW},
357
358     /* Common resources */
359     {DtNactivateCallback, DtCCallback, XmRCallback, sizeof(XtCallbackList),
360          DtOffset(activate_callback), XmRCallback, 
361          (XtPointer)NULL},
362     {DtNalignment, DtCAlignment, XmRAlignment, sizeof(unsigned char),
363          DtOffset(alignment), XmRImmediate, 
364          (XtPointer)DtALIGNMENT_BEGINNING},
365     {DtNarrowLayout, DtCArrowLayout, DtRArrowLayout, sizeof(unsigned char),
366          DtOffset(arrow_layout), XmRImmediate, 
367          (XtPointer)DtARROWS_END},
368     {DtNarrowSensitivity, DtCArrowSensitivity, DtRArrowSensitivity,
369          sizeof(unsigned char), DtOffset(arrow_sensitivity),
370          XmRImmediate, (XtPointer)DtARROWS_SENSITIVE},
371     {DtNspinBoxChildType, DtCSpinBoxChildType, DtRSpinBoxChildType, 
372          sizeof(unsigned char),
373          DtOffset(child_type), XmRImmediate, (XtPointer)DtSTRING},
374     {DtNcolumns, DtCColumns, XmRShort, sizeof(short),
375          DtOffset(text_columns), XmRImmediate, (XtPointer)DEFAULT_COL},
376     {DtNdecimalPoints, DtCDecimalPoints, XmRShort, sizeof( short ),
377          DtOffset(decimal_points), XmRImmediate, (XtPointer)0},
378     {DtNeditable, DtCEditable, XmRBoolean, sizeof(Boolean),
379          DtOffset(editable), XmRImmediate, (XtPointer)TRUE},
380     {DtNfocusCallback, DtCCallback, XmRCallback, sizeof(XtCallbackList),
381          DtOffset(focus_callback), XmRCallback, 
382          (XtPointer)NULL},
383     {DtNincrementValue, DtCIncrementValue, XmRInt, sizeof(int),
384          DtOffset(numeric_increment), XmRImmediate, (XtPointer)1},
385     {DtNinitialDelay, DtCInitialDelay, XmRInt, sizeof(unsigned int),
386          DtOffset(initial_delay), XmRImmediate, (XtPointer)250},
387     {DtNnumValues, DtCNumValues, DtRNumValues, sizeof(int),
388          DtOffset(item_count), XmRImmediate, (XtPointer)0},
389     {DtNvalues, DtCItems, XmRXmStringTable, sizeof(XmStringTable),
390          DtOffset(items), XmRImmediate, (XtPointer)NULL},
391     {DtNlosingFocusCallback, DtCCallback, XmRCallback, sizeof(XtCallbackList),
392          DtOffset(losing_focus_callback), XmRCallback, 
393          (XtPointer)NULL},
394     {DtNmarginHeight, DtCMarginHeight, XmRVerticalDimension, sizeof(Dimension),
395          DtOffset(margin_height), XmRImmediate, (XtPointer)MARGIN},
396     {DtNmarginWidth, DtCMarginWidth, XmRHorizontalDimension, sizeof(Dimension),
397          DtOffset(margin_width), XmRImmediate, (XtPointer)MARGIN},
398     {DtNmaximumValue, DtCMaximumValue, XmRInt, sizeof(int), 
399          DtOffset(maximum), XmRImmediate, (XtPointer)10},
400     {DtNmaxLength, DtCMaxLength, XmRInt, sizeof(int),
401          DtOffset(text_max_length), XmRImmediate, (XtPointer)MAXINT},
402     {DtNminimumValue, DtCMinimumValue, XmRInt, sizeof(int), 
403          DtOffset(minimum), XmRImmediate, (XtPointer)0},
404     {DtNmodifyVerifyCallback, DtCCallback, XmRCallback, 
405          sizeof(XtCallbackList), DtOffset(modify_verify_callback),
406          XmRCallback, (XtPointer)NULL},
407     {DtNposition, DtCPosition, XmRInt, sizeof(int),
408          DtOffset(position), XmRImmediate, (XtPointer)0},
409     {DtNrecomputeSize, DtCRecomputeSize, XmRBoolean, sizeof(Boolean),
410          DtOffset(recompute_size), XmRImmediate, (XtPointer)TRUE},
411     {DtNrepeatDelay, DtCRepeatDelay, XmRInt, sizeof(unsigned int),
412          DtOffset(repeat_delay), XmRImmediate, (XtPointer)200},
413     {DtNtextField, DtCTextField, XmRWidget, sizeof(Widget),
414          DtOffset(text), XmRImmediate, (XtPointer)NULL},
415     {DtNvalueChangedCallback, DtCCallback, XmRCallback, 
416          sizeof(XtCallbackList), DtOffset(value_changed_callback),
417          XmRCallback, (XtPointer)NULL},
418     {DtNwrap, DtCWrap, XmRBoolean, sizeof(Boolean),
419          DtOffset(wrap), XmRImmediate, (XtPointer)TRUE},
420 };
421
422 /* Synthetic resources.  Only used for Motif API arrowSize right now */
423 static XmSyntheticResource syn_resources[] = {
424     {DtNarrowSize, sizeof(Dimension), DtOffset(arrow_size), 
425          _DtSpinBoxGetArrowSize, _XmSetSyntheticResForChild},
426     {DtNmarginHeight, sizeof(Dimension), DtOffset(margin_height),
427         XmeFromVerticalPixels, XmeToVerticalPixels},
428     {DtNmarginWidth, sizeof(Dimension), DtOffset(margin_width),
429         XmeFromHorizontalPixels, XmeToHorizontalPixels},
430 };
431 #undef DtOffset
432 #undef offset
433
434 /* Need Class Extension for widget navigation */
435 static XmBaseClassExtRec baseClassExtRec = {
436     NULL,
437     NULLQUARK,
438     XmBaseClassExtVersion,
439     sizeof(XmBaseClassExtRec),
440     (XtInitProc)NULL,                   /* InitializePrehook    */
441     (XtSetValuesFunc)NULL,              /* SetValuesPrehook     */
442     (XtInitProc)NULL,                   /* InitializePosthook   */
443     (XtSetValuesFunc)NULL,              /* SetValuesPosthook    */
444     NULL,                               /* secondaryObjectClass */
445     (XtInitProc)NULL,                   /* secondaryCreate      */
446     (XmGetSecResDataFunc)NULL,          /* getSecRes data       */
447     { 0 },                              /* fastSubclass flags   */
448     (XtArgsProc)NULL,                   /* getValuesPrehook     */
449     (XtArgsProc)NULL,                   /* getValuesPosthook    */
450     (XtWidgetClassProc)NULL,            /* classPartInitPrehook */
451     (XtWidgetClassProc)NULL,            /* classPartInitPosthook*/
452     NULL,                               /* ext_resources        */
453     NULL,                               /* compiled_ext_resources*/
454     0,                                  /* num_ext_resources    */
455     FALSE,                              /* use_sub_resources    */
456     (XmWidgetNavigableProc)WidgetNavigable,
457                                         /* widgetNavigable      */
458     (XmFocusChangeProc)NULL,            /* focusChange          */
459     (XmWrapperData)NULL                 /* wrapperData          */
460 };
461
462 /*
463  * Define Class Record.
464  */
465 externaldef(dtspinboxclassrec) DtSpinBoxClassRec dtSpinBoxClassRec =
466 {
467     {           /* core_class fields      */
468     (WidgetClass)&(xmManagerClassRec),          /* superclass         */    
469     (String)"DtSpinBox",                        /* class_name         */    
470     (Cardinal)sizeof(DtSpinBoxPart),            /* widget_size        */    
471     (XtProc)ClassInitialize,                    /* class_initialize   */    
472     (XtWidgetClassProc)NULL,                    /* class_part_init    */    
473     (XtEnum)FALSE,                              /* class_inited       */    
474     (XtInitProc)Initialize,                     /* initialize         */    
475     (XtArgsProc)NULL,                           /* initialize_hook    */    
476     (XtRealizeProc)XtInheritRealize,            /* realize            */    
477     (XtActionList)SpinBoxActionTable,           /* actions            */    
478     (Cardinal)XtNumber(SpinBoxActionTable),     /* num_actions        */    
479     (XtResourceList)resources,                  /* resources          */    
480     (Cardinal)XtNumber(resources),              /* num_resources      */    
481     (XrmClass)NULLQUARK,                        /* xrm_class          */    
482     (Boolean)TRUE,                              /* compress_motion    */    
483     (XtEnum)XtExposeCompressMaximal,            /* compress_exposure  */    
484     (Boolean)TRUE,                              /* compress_enterleave*/    
485     (Boolean)FALSE,                             /* visible_interest   */    
486     (XtWidgetProc)Destroy,                      /* destroy            */    
487     (XtWidgetProc)Resize,                       /* resize             */    
488     (XtExposeProc)Redisplay,                    /* expose             */    
489     (XtSetValuesFunc)SetValues,                 /* set_values         */    
490     (XtArgsFunc)NULL,                           /* set values hook    */    
491     (XtAlmostProc)XtInheritSetValuesAlmost,     /* set values almost  */    
492     (XtArgsProc)NULL,                           /* get values hook    */    
493     (XtAcceptFocusProc)NULL,                    /* accept_focus       */    
494     (XtVersionType)XtVersionDontCheck,          /* Version            */    
495     (XtPointer)NULL,                            /* PRIVATE cb list    */
496     (String)XtInheritTranslations,              /* tm_table           */
497     (XtGeometryHandler)XtInheritQueryGeometry,  /* query_geom         */
498     (XtStringProc)XtInheritDisplayAccelerator,  /* display_accelerator*/
499     (XtPointer)&baseClassExtRec                 /* extension          */
500     },
501     {           /* composite_class fields */
502     (XtGeometryHandler)GeometryManager,         /* geometry_manager   */     
503     (XtWidgetProc)XtInheritChangeManaged,       /* change_managed     */     
504     (XtWidgetProc)XtInheritInsertChild,         /* insert_child       */     
505     (XtWidgetProc)XtInheritDeleteChild,         /* delete_child       */     
506     (XtPointer)NULL                             /* extension          */     
507     },
508     {           /* constraint_class fields */
509     (XtResourceList)NULL,                       /* resources          */     
510     (Cardinal)0,                                /* num_resources      */     
511     (Cardinal)0,                                /* constraint_size    */     
512     (XtInitProc)NULL,                           /* initialize         */     
513     (XtWidgetProc)NULL,                         /* destroy            */     
514     (XtSetValuesFunc)NULL,                      /* set_values         */     
515     (XtPointer)NULL                             /* extension          */     
516     },
517     {           /* manager class     */
518     (String)XtInheritTranslations,              /* translations       */     
519     (XmSyntheticResource*)syn_resources,        /* syn resources      */     
520     (int)XtNumber(syn_resources),               /* num syn_resources  */     
521     (XmSyntheticResource*)NULL,                 /* get_cont_resources */     
522     (int)0,                                     /* num_get_cont_resources */ 
523     (XmParentProcessProc)XmInheritParentProcess,/* parent_process     */     
524     (XtPointer)NULL                             /* extension          */     
525     },
526     {           /* spin_box_class fields */     
527     (Boolean)0,
528     }
529 };
530
531 externaldef(dtspinboxwidgetclass) WidgetClass dtSpinBoxWidgetClass =
532                                                 (WidgetClass)&dtSpinBoxClassRec;
533
534 static XmRepTypeId _DtRID_SB_ARROW_SENSITIVITY_TYPE;
535 static String _DtArrowSensitivityNames[] = {
536         "arrows_insensitive",
537         "arrows_increment_sensitive",
538         "arrows_decrement_sensitive",
539         "arrows_sensitive"
540 };
541
542 /* 
543  * Must set up the record type for the class extensions to work.
544  */
545 static void
546 ClassInitialize(void)
547 {
548     baseClassExtRec.record_type = XmQmotif;
549 /*
550  * MotifBc
551  */
552     XmResolveAllPartOffsets(dtSpinBoxWidgetClass, &ipot, &cpot);
553
554     child_trans = XtParseTranslationTable(SpinBoxChildTranslationTable);
555     spin_trans = XtParseTranslationTable(SpinBoxTranslationTable);
556
557     child_trans_label=XtParseTranslationTable(SpinBoxLabelTranslationTable);
558     child_trans_text=XtParseTranslationTable(SpinBoxTextTranslationTable);
559     child_trans_arrow=XtParseTranslationTable(SpinBoxArrowTranslationTable);
560
561     _DtRID_SB_ARROW_SENSITIVITY_TYPE =
562       XmRepTypeRegister(DtRArrowSensitivity, _DtArrowSensitivityNames,
563                         NULL, XtNumber(_DtArrowSensitivityNames));
564
565     InitLabel = XmStringCreateLocalized(SB_LABEL);
566 }
567
568 /*
569  * SpinBox initialization function.  This builds the widgets inside
570  * our widget, to get the correct layout.  If the editable resource
571  * is TRUE, we create a textField; if FALSE, we create a label.  If the
572  * user changes this resource later, we will create the other widget
573  * (textField or Label).  We don't want to carry backage from both
574  * widgets if the user never changes the editable resource.
575  */
576 static void
577 Initialize(     DtSpinBoxWidget request,
578                 DtSpinBoxWidget new,
579                 ArgList given_args,
580                 Cardinal *num_args)
581 {   /* MotifBc */
582     DtSpinBoxPart *spin_p = (DtSpinBoxPart*)
583         &(XmField(new,ipot,DtSpinBox,label,Widget));
584     char *widget_name;
585     Arg args[20];
586     int n;
587     /* Resolution Independent */
588     unsigned char unit_type = MUnitType(new);
589
590     /* Overwrite the manager's focusIn and focusOut translations */
591     XtOverrideTranslations((Widget)new, spin_trans);
592
593     widget_name = XtMalloc(strlen(XtName((Widget)new)) + 10);
594
595     Text(new) = (Widget)NULL;
596     Label(new) = (Widget)NULL;
597     OldWidth(new) = 0;
598     OldHeight(new) = 0;
599     InitCb(new) = TRUE;
600     Grabbed(new) = FALSE;
601
602     CheckResources(new);
603
604     /*
605      * Create the text or label depending on editable resource.
606      */
607     if (Editable(new)) {
608         sprintf(widget_name, "%s_TF", XtName((Widget)new));
609         n = 0;
610         XtSetArg(args[n], XmNmaxLength, TextMaxLength(new)); n++;
611         XtSetArg(args[n], XmNmarginWidth, TEXT_CONTEXT_MARGIN); n++;
612         XtSetArg(args[n], XmNmarginHeight, 2); n++;
613         /* Resolution Independent */
614         if (unit_type != XmPIXELS) {
615                 XtSetArg(args[n], XmNunitType, XmPIXELS); n++;
616         }
617         Text(new) = XtCreateManagedWidget(widget_name,
618                                              xmTextFieldWidgetClass,
619                                              (Widget)new, args, n);
620         XtAddCallback(Text(new), XmNlosingFocusCallback, 
621                       text_losing_focus_cb, (XtPointer)new);
622         XtAddCallback(Text(new), XmNactivateCallback, 
623                       text_activate_cb, (XtPointer)new);
624         XtAddCallback(Text(new), XmNfocusCallback, 
625                       text_focus_cb, (XtPointer)new);
626
627         if (TextColumns(request) == DEFAULT_COL && Width(request)) {
628                 Dimension width;
629                 CalculateSizes(new, &width, NULL, NULL);
630                 XtSetArg(args[n], XmNwidth, width); n++;
631         }
632         else {
633                 XtSetArg(args[n], XmNcolumns, TextColumns(new)); n++;
634         }
635         if (unit_type != XmPIXELS) {
636                 XtSetArg(args[n], XmNunitType, unit_type); n++;
637         }                
638         XtSetValues(Text(new), args, n);
639     }
640     else {
641         sprintf(widget_name, "%s_Label", XtName((Widget)new));
642         SPIN_SHADOW(new) = LABEL_SHADOW;
643         n = 0;
644         XtSetArg(args[n], XmNalignment, Alignment(new)); n++;
645         XtSetArg(args[n], XmNrecomputeSize, FALSE); n++;
646         XtSetArg(args[n], XmNlabelString, InitLabel); n++;
647         XtSetArg(args[n], XmNmarginLeft, LABEL_PADDING); n++;
648         XtSetArg(args[n], XmNmarginRight, LABEL_PADDING); n++;
649         XtSetArg(args[n], XmNmarginWidth, TEXT_CONTEXT_MARGIN); n++;
650         XtSetArg(args[n], XmNmarginHeight, 2); n++;
651         if (unit_type != XmPIXELS) {
652                 XtSetArg(args[n], XmNunitType, XmPIXELS); n++;
653         }
654         Label(new) = XtCreateManagedWidget(widget_name, xmLabelWidgetClass,
655                                               (Widget)new, args, n);
656
657         if (unit_type != XmPIXELS) {
658                 XtSetArg(args[n], XmNunitType, unit_type); n++;
659         }                
660         if (Width(new)) {
661                 Dimension width;
662                 CalculateSizes(new, &width, NULL, NULL);
663                 XtSetArg(args[n], XmNwidth,  width); n++;
664         }
665         if (n>0)
666                 XtSetValues(Label(new), args, n);
667     }
668
669     /*
670      * Create the 2 ArrowWidgets.
671      */
672     sprintf(widget_name, "%s_Up", XtName((Widget)new));
673     n = 0;
674     if (ArrowLayout(new) == DtARROWS_SPLIT) {
675         XtSetArg(args[n], XmNarrowDirection, XmARROW_RIGHT); n++;
676     }
677     XtSetArg(args[n], XmNhighlightThickness, 0); n++;
678     XtSetArg(args[n], XmNshadowThickness, 0); n++;
679     XtSetArg(args[n], XmNtraversalOn, FALSE); n++;
680     XtSetArg(args[n], XmNforeground, CBgPixel(new)); n++;
681     UpArrow(new) = XtCreateManagedWidget(widget_name, 
682                                              xmArrowButtonWidgetClass,
683                                              (Widget)new, args, n);
684     XtOverrideTranslations((Widget)UpArrow(new), child_trans_arrow);
685
686     sprintf(widget_name, "%s_Down", XtName((Widget)new));
687     if (ArrowLayout(new) == DtARROWS_SPLIT) {
688         XtSetArg(args[n], XmNarrowDirection, XmARROW_LEFT); n++;
689     }
690     else {
691         XtSetArg(args[n], XmNarrowDirection, XmARROW_DOWN); n++;
692     }
693     DownArrow(new) = XtCreateManagedWidget(widget_name, 
694                                                xmArrowButtonWidgetClass,
695                                                (Widget)new, args, n);
696     XtOverrideTranslations((Widget)DownArrow(new), child_trans_arrow);
697
698     /* Set sensitivity of arrows (up arrow is right arrow) */
699     if ((ArrowSensitivity(new) == DtARROWS_INSENSITIVE) ||
700         (ArrowSensitivity(new) == DtARROWS_DECREMENT_SENSITIVE)) 
701         XtSetSensitive(UpArrow(new), FALSE);
702     if ((ArrowSensitivity(new) == DtARROWS_INSENSITIVE) ||
703         (ArrowSensitivity(new) == DtARROWS_INCREMENT_SENSITIVE)) 
704         XtSetSensitive(DownArrow(new), FALSE);
705
706     /* 
707      * Arm causes the value to change and the timer to start.
708      * Disarm (leaveNotify from grab) causes the timer to stop.
709      */
710     XtAddCallback(UpArrow(new), XmNarmCallback, up_cb, (XtPointer)new);
711     XtAddCallback(UpArrow(new), XmNdisarmCallback, disarm_cb, 
712                   (XtPointer)new);
713     XtAddEventHandler(UpArrow(new), LeaveWindowMask, FALSE, grab_leave_cb, 
714                       (XtPointer)new);
715     XtAddCallback(DownArrow(new), XmNarmCallback, down_cb, (XtPointer)new);
716     XtAddCallback(DownArrow(new), XmNdisarmCallback, disarm_cb, 
717                   (XtPointer)new);
718     XtAddEventHandler(DownArrow(new), LeaveWindowMask, FALSE, 
719                       grab_leave_cb, (XtPointer)new);
720
721     /* Initialize everything based on what the resource values are */
722     StoreResourceInfo(spin_p, NULL, TRUE);
723
724     /*
725      * Set initial value in text or label if items was specified
726      */
727     if (Editable(new) == FALSE) {
728         SetLabelData(new);
729         SetMaximumLabelSize(spin_p);
730     }
731     else
732     {
733         SetTextFieldData(new);
734     }
735     SetSpinBoxSize(new);
736     LayoutChildren(new);
737     XtFree(widget_name);
738
739     /* Store Converter for DtNmaximumValue, DtNminimumValue, DtNincrementValue,
740      */
741     XtSetTypeConverter(XmRString, DtRMaximumValue, XtCvtStringToInt, NULL, 0, 
742             XtCacheAll, NULL);
743     XtSetTypeConverter(XmRString, DtRMinimumValue, XtCvtStringToInt, NULL, 0, 
744             XtCacheAll, NULL);
745     XtSetTypeConverter(XmRString, DtRIncrementValue, XtCvtStringToInt, NULL, 0, 
746             XtCacheAll, NULL);
747     XtSetTypeConverter(XmRString, DtRNumValues, XtCvtStringToInt, NULL, 0, 
748             XtCacheAll, NULL);
749     /*
750      * this is so these resources can be set uniformly through XtCreateWidget
751      * or through defaults file as *spin.backgound
752      */
753
754     n=0;
755     XtSetArg(args[n],XmNbackground,CBgPixel(new));n++;
756     XtSetArg(args[n],XmNbackgroundPixmap,CBgPixmap(new));n++;
757     XtSetArg(args[n],XmNforeground,MFgPixel(new));n++;
758     if(Text(new))
759         XtSetValues (Text(new),args,n);
760     if(Label(new))
761         XtSetValues (Label(new),args,n);
762     if(UpArrow(new))
763         XtSetValues (UpArrow(new),args,n);
764     if(DownArrow(new))
765         XtSetValues (DownArrow(new),args,n);
766
767 }
768
769
770 /*
771  * Allow the manager to gain focus if not editable.  If editable (using
772  * text-field), then let the toolkit give focus to the text-field.
773  */
774 static XmNavigability
775 WidgetNavigable(DtSpinBoxWidget spin)
776 {   
777     XmNavigationType nav_type = ((XmManagerWidget)spin)->manager.navigation_type;
778
779     if (spin->core.sensitive &&  spin->core.ancestor_sensitive &&
780         ((XmManagerWidget)spin)->manager.traversal_on) {
781         if ((nav_type == XmSTICKY_TAB_GROUP) ||
782             (nav_type == XmEXCLUSIVE_TAB_GROUP) ||
783             ((nav_type == XmTAB_GROUP) &&
784              !_XmShellIsExclusive((Widget)spin))) {
785             if (Editable(spin))
786                 return(XmDESCENDANTS_TAB_NAVIGABLE);
787             else
788                 return(XmTAB_NAVIGABLE);
789         }
790         return(XmDESCENDANTS_NAVIGABLE);
791     }
792     return(XmNOT_NAVIGABLE);
793 }
794
795 /* 
796  * The spin_box gets focus.
797  */
798 static void 
799 _SpinBoxFocusIn(        DtSpinBoxWidget spin,
800                         XEvent *event,
801                         char **params,
802                         Cardinal *num_params)
803 {
804     DrawHighlight(spin, FALSE);
805 }
806
807 /* 
808  * The spin_box loses focus.
809  */
810 static void 
811 _SpinBoxFocusOut(       DtSpinBoxWidget spin,
812                         XEvent *event,
813                         char **params,
814                         Cardinal *num_params)
815 {
816     DrawHighlight(spin, TRUE);
817 }
818
819 /*
820  * This function gets called whenever we draw or clear the shadow (to
821  * redraw highlight during resize, etc), as well as during focus_in
822  * and focus_out events.
823  */
824 static void
825 DrawHighlight(  DtSpinBoxWidget spin,
826                 Boolean clear)
827 {
828     XRectangle rect[4] ;
829
830     if (XtIsRealized((Widget)spin)) {
831         if (clear) {
832             rect[0].x = rect[1].x = rect[2].x = 0;
833             rect[3].x = OldWidth(spin) - SPIN_MARGIN_W(spin);
834             rect[0].y = rect[2].y = rect[3].y = 0 ;
835             rect[1].y = OldHeight(spin) - SPIN_MARGIN_H(spin);
836             rect[0].width = rect[1].width = OldWidth(spin);
837             rect[2].width = rect[3].width = SPIN_MARGIN_W(spin);
838             rect[0].height = rect[1].height = SPIN_MARGIN_H(spin);
839             rect[2].height = rect[3].height = OldHeight(spin);
840             XFillRectangles(XtDisplayOfObject((Widget)spin),
841                             XtWindowOfObject((Widget)spin), 
842                             spin->manager.background_GC, rect, 4);
843         }
844         else if (XmGetFocusWidget((Widget)spin) == (Widget)spin) {
845             rect[0].x = rect[1].x = rect[2].x = 0;
846             rect[3].x = XtWidth(spin) - SPIN_MARGIN_W(spin);
847             rect[0].y = rect[2].y = rect[3].y = 0 ;
848             rect[1].y = XtHeight(spin) - SPIN_MARGIN_H(spin);
849             rect[0].width = rect[1].width = XtWidth(spin);
850             rect[2].width = rect[3].width = SPIN_MARGIN_W(spin);
851             rect[0].height = rect[1].height = SPIN_MARGIN_H(spin);
852             rect[2].height = rect[3].height = XtHeight(spin);
853             XFillRectangles(XtDisplayOfObject((Widget)spin),
854                             XtWindowOfObject((Widget)spin), 
855                             spin->manager.highlight_GC, rect, 4);
856         }
857     }
858 }
859
860
861 /*
862  * osfUp virtual key hit.  Simulate hitting the up arrow.
863  */
864 static void 
865 _SpinBoxUp(     DtSpinBoxWidget spin,
866                 XEvent *event,
867                 char **params,
868                 Cardinal *num_params)
869 {
870     if (*num_params != 0) /* params means label or arrows */
871         spin = (DtSpinBoxWidget)XtParent(spin);
872
873     if (ArrowLayout(spin) != DtARROWS_SPLIT) {
874         up_cb((Widget)UpArrow(spin), (XtPointer)spin, NULL);
875         disarm_cb((Widget)UpArrow(spin), (XtPointer)spin, NULL);
876     }
877 }
878
879 /*
880  * osfDown virtual key hit.  Simulate hitting the down arrow.
881  */
882 static void 
883 _SpinBoxDown(DtSpinBoxWidget spin,
884                 XEvent *event,
885                 char **params,
886                 Cardinal *num_params)
887 {
888     if (*num_params != 0) /* params means label or arrows */
889         spin = (DtSpinBoxWidget)XtParent(spin);
890
891     if (ArrowLayout(spin) != DtARROWS_SPLIT) {
892         down_cb((Widget)DownArrow(spin), (XtPointer)spin, NULL);
893         disarm_cb((Widget)DownArrow(spin), (XtPointer)spin, NULL);
894     }
895 }
896
897 /*
898  * osfRight virtual key hit.  Simulate hitting the up arrow.
899  */
900 static void 
901 _SpinBoxRight(DtSpinBoxWidget spin,
902                 XEvent *event,
903                 char **params,
904                 Cardinal *num_params)
905 {
906     if (*num_params != 0) /* params means label or arrows */
907         spin = (DtSpinBoxWidget)XtParent(spin);
908
909     if (ArrowLayout(spin) == DtARROWS_SPLIT) {
910         up_cb((Widget)UpArrow(spin), (XtPointer)spin, NULL);
911         disarm_cb((Widget)UpArrow(spin), (XtPointer)spin, NULL);
912     }
913 }
914
915 /*
916  * osfLeft virtual key hit.  Simulate hitting the down arrow.
917  */
918 static void 
919 _SpinBoxLeft(DtSpinBoxWidget spin,
920                 XEvent *event,
921                 char **params,
922                 Cardinal *num_params)
923 {
924     if (*num_params != 0) /* params means label or arrows */
925         spin = (DtSpinBoxWidget)XtParent(spin);
926
927     if (ArrowLayout(spin) == DtARROWS_SPLIT) {
928         down_cb((Widget)DownArrow(spin), (XtPointer)spin, NULL);
929         disarm_cb((Widget)DownArrow(spin), (XtPointer)spin, NULL);
930     }
931 }
932
933 /*
934  * osfBeginLine virtual key hit.  Go to first item.
935  */
936 static void 
937 _SpinBoxBeginLine(      DtSpinBoxWidget spin,
938                         XEvent *event,
939                         char **params,
940                         Cardinal *num_params)
941 {
942     int new_position;
943     float new_current;
944     
945     if (*num_params != 0) /* params means label or arrows */
946         spin = (DtSpinBoxWidget)XtParent(spin);
947
948     if (ChildType(spin) == DtNUMERIC) {
949         new_position = Minimum(spin);
950         new_current = Min(spin);
951     }
952     else {
953         new_position = 0;
954     }
955     if (SendCallback(spin, event, FALSE, new_position,
956                      new_current, FALSE) == TRUE) {
957         /* User said yes, so set widget values */
958         Position(spin) = new_position;
959         Current(spin) = new_current;
960         if (Editable(spin))
961             SetTextFieldData(spin);
962         else
963             SetLabelData(spin);
964         
965         /* send value_changed callback */
966         (void)SendCallback(spin, event, TRUE, Position(spin),
967                            Current(spin), FALSE);
968     }
969 }
970
971 /*
972  * osfEndLine virtual key hit.  Go to last item.
973  */
974 static void 
975 _SpinBoxEndLine(        DtSpinBoxWidget spin,
976                         XEvent *event,
977                         char **params,
978                         Cardinal *num_params)
979 {
980     int new_position;
981     float new_current;
982     
983     if (*num_params != 0) /* params means label or arrows */
984         spin = (DtSpinBoxWidget)XtParent(spin);
985
986     if (ChildType(spin) == DtNUMERIC) {
987         new_position = Maximum(spin);
988         new_current = Max(spin);
989     }
990     else {
991         new_position = ItemCount(spin) - 1;
992     }
993     if (SendCallback(spin, event, FALSE, new_position,
994                      new_current, FALSE) == TRUE) {
995         /* User said yes, so set widget values */
996         Position(spin) = new_position;
997         Current(spin) = new_current;
998         if (Editable(spin))
999             SetTextFieldData(spin);
1000         else
1001             SetLabelData(spin);
1002         
1003         /* send value_changed callback */
1004         (void)SendCallback(spin, event, TRUE, Position(spin),
1005                            Current(spin), FALSE);
1006     }
1007 }
1008 /*
1009  * Legacy: Get Focus for SpinBox when hit its label part
1010  */
1011 static void
1012 _SpinBoxGetFocus(     DtSpinBoxWidget spin,
1013                         XEvent *event,
1014                         char **params,
1015                         Cardinal *num_params)
1016 {
1017     XmProcessTraversal((Widget)XtParent(spin),
1018                         (XmTraversalDirection) XmTRAVERSE_CURRENT);
1019 }
1020
1021 /*
1022  * Legacy: Process Focus Traversal for SpinBox when cursor is in its arrow part
1023  */
1024 static void
1025 _SpinBoxPrevTabGroup(DtSpinBoxWidget spin,
1026                         XEvent *event,
1027                         char **params,
1028                         Cardinal *num_params)
1029 {
1030     XmProcessTraversal((Widget)XtParent(spin),
1031                         (XmTraversalDirection) XmTRAVERSE_PREV_TAB_GROUP);
1032 }
1033
1034 static void
1035 _SpinBoxNextTabGroup(DtSpinBoxWidget spin,
1036                         XEvent *event,
1037                         char **params,
1038                         Cardinal *num_params)
1039 {
1040     XmProcessTraversal((Widget)XtParent(spin),
1041                         (XmTraversalDirection) XmTRAVERSE_NEXT_TAB_GROUP);
1042 }
1043
1044 /*
1045  * This function goes through most of the resources and makes sure 
1046  * they have legal values.
1047  */
1048 static void
1049 CheckResources(DtSpinBoxWidget spin)
1050 {
1051     if (!XmRepTypeValidValue(_DtRID_SB_ARROW_SENSITIVITY_TYPE,
1052                              ArrowSensitivity(spin), (Widget)spin)) {
1053         XtWarning(SB_ARROW_SENSITIVE);
1054         ArrowSensitivity(spin) = DtARROWS_SENSITIVE;
1055     }
1056     if ((Alignment(spin) != DtALIGNMENT_CENTER) && 
1057         (Alignment(spin) != DtALIGNMENT_BEGINNING) &&
1058         (Alignment(spin) != DtALIGNMENT_END)) {
1059         XtWarning(SB_ALIGNMENT);
1060         Alignment(spin) = DtALIGNMENT_CENTER;
1061     }
1062     if (InitialDelay(spin) == 0) {
1063         XtWarning(SB_INIT_DELAY);
1064         InitialDelay(spin) = 250;
1065     }
1066     if ((ArrowLayout(spin) != DtARROWS_FLAT_BEGINNING) && 
1067         (ArrowLayout(spin) != DtARROWS_FLAT_END) &&
1068         (ArrowLayout(spin) != DtARROWS_SPLIT) &&
1069         (ArrowLayout(spin) != DtARROWS_BEGINNING) &&
1070         (ArrowLayout(spin) != DtARROWS_END)) {
1071         XtWarning(SB_ARROW_LAYOUT);
1072         ArrowLayout(spin) = DtARROWS_BEGINNING;
1073     }
1074     if (RepeatDelay(spin) == 0) {
1075         XtWarning(SB_REPEAT_DELAY);
1076         RepeatDelay(spin) = 200;
1077     }
1078     if (ItemCount(spin) < 0) {
1079         XtWarning(SB_ITEM_COUNT);
1080         ItemCount(spin) = 0;
1081     }
1082     if ((ChildType(spin) == DtSTRING) &&
1083         ((Position(spin) < 0) ||
1084          ((Position(spin) >= ItemCount(spin)) &&
1085           (ItemCount(spin) > 0)))) {
1086         XtWarning(SB_POSITION_STRING);
1087         Position(spin) = 0;
1088     }
1089     if ((DecimalPoints(spin) < 0) ||
1090         (DecimalPoints(spin) > MAX_FLOAT_DECIMALS)) {
1091         XtWarning(SB_DECIMAL_POINTS);
1092         DecimalPoints(spin) = 0;
1093     }
1094     if (Minimum(spin) > Maximum(spin)) {
1095         XtWarning(SB_MIN_MAX);
1096         Minimum(spin) = Maximum(spin);
1097     }
1098     if ((ChildType(spin) == DtNUMERIC) &&
1099         ((Position(spin) < Minimum(spin)) ||
1100          (Position(spin) > Maximum(spin)) ||
1101          ((Position(spin) % NumericIncrement(spin)) != 0))) {
1102         XtWarning(SB_POSITION_NUMERIC);
1103         Position(spin) = Minimum(spin);
1104     }
1105 }
1106
1107
1108 /*
1109  * Destroy procedure called by the toolkit.
1110  */
1111 static void 
1112 Destroy(DtSpinBoxWidget spin)
1113 {
1114     int i;
1115
1116     if ((int)Timer(spin))
1117       {
1118         XtRemoveTimeOut(Timer(spin));
1119         Timer(spin) = (XtIntervalId)NULL;
1120       }
1121
1122     if (ItemCount(spin)>0) {
1123         for (i = 0; i < ItemCount(spin); i++) {
1124             XmStringFree((Items(spin))[i]);
1125             }
1126         XtFree((char*)(Items(spin)));
1127     }
1128
1129     /*
1130      * Don't remove callbacks and event handlers set on the children,
1131      * this has already been done by Xt (children are cleaned up before
1132      * the parent).
1133      */
1134 }
1135
1136
1137 /*
1138  * Resize function called by toolkit.  The size of our spin-box
1139  * has already been changed.  That is why we must store 
1140  * old_width and old_height.
1141  */
1142 static void
1143 Resize(DtSpinBoxWidget spin)
1144 {
1145     ClearShadow(spin, TRUE);
1146     LayoutChildren(spin);
1147     DrawShadow(spin);
1148     OldWidth(spin) = spin->core.width;
1149     OldHeight(spin) = spin->core.height;
1150 }
1151
1152
1153 /*
1154  * Redisplay function called by toolkit. The widget didn't change size, 
1155  * so just redisplay the shadow.
1156  */
1157 static void
1158 Redisplay(      DtSpinBoxWidget w,
1159                 XEvent *event,
1160                 Region region)
1161 {
1162     DrawShadow(w);
1163 }
1164
1165
1166 /*
1167  * GeometryManager function called by toolkit when a child resizes/moves.
1168  * We are not allowing any changes but width/height of the text-field.
1169  * this is because the user can retrieve the text-field and make changes
1170  * that we want to honor.  If they mess around with the label or arrow,
1171  * then we won't honor the request.
1172  * If the text-field requests a change, then make the change, and allow
1173  * our SetSpinBoxSize() and LayoutChildren() figure out what size will
1174  * be allowed.
1175  * Returning GeometryDone was suppose to tell the toolkit
1176  * that we resized the child ourselves, but the text-field had trouble
1177  * with this (its' geometry_manager wasn't called or working right?), so
1178  * we return GeometryYes.
1179  */
1180 static XtGeometryResult
1181 GeometryManager(Widget w, /* child */
1182                 XtWidgetGeometry *request,
1183                 XtWidgetGeometry *reply)
1184 {
1185     /* MotifBc */
1186     DtSpinBoxWidget spin = (DtSpinBoxWidget)XtParent(w);
1187     /* Resolution Independent */
1188     Arg args[4];
1189     Dimension width, height, border_width;
1190     int n;
1191     unsigned char unit_type;
1192
1193     /* Ignore everything but text-field */
1194     if (w != Text(spin) ) {
1195         return(XtGeometryNo);
1196     }
1197
1198     /* Only allow width/height changes */
1199     if (!(request->request_mode & (CWWidth | CWHeight)))
1200         return(XtGeometryNo);
1201     
1202     /* Resolution Independent */
1203     XtSetArg(args[0], XmNunitType, &unit_type);
1204     XtGetValues(w, args, 1);
1205     if ( unit_type != XmPIXELS) {
1206         XtSetArg(args[0], XmNunitType, XmPIXELS);
1207         XtSetValues(w, args, 1);
1208     }
1209     n = 0;
1210     /* Set the text-field to the requested size */
1211     if (request->request_mode & CWWidth) {
1212         /* MotifBc */
1213         XtSetArg(args[n], XmNwidth, &width); n++;
1214     }
1215     if (request->request_mode & CWHeight) {
1216         /* MotifBc */
1217         XtSetArg(args[n], XmNheight, &height); n++;
1218     }
1219     /* MotifBc */
1220     XtSetArg(args[n], XmNborderWidth, &border_width); n++;
1221     XtGetValues(w, args, n);
1222     XtResizeWidget(w, width, height, border_width);
1223     if ( unit_type != XmPIXELS) {
1224         XtSetArg(args[0], XmNunitType, unit_type);
1225         XtSetValues(w, args, 1);
1226     }
1227     
1228     ClearShadow(spin, TRUE);
1229     if (RecomputeSize(spin))
1230         SetSpinBoxSize(spin);
1231     LayoutChildren(spin);
1232     DrawShadow(spin);
1233     return(XtGeometryDone);
1234 }
1235
1236 /* 
1237  * This function sets the size of the spin_box widget based on the
1238  * current size of the children.  Don't worry if it doesn't work, the
1239  * children will be squeezed in later.
1240  */
1241 static void
1242 SetSpinBoxSize(DtSpinBoxWidget spin)
1243 {
1244     Widget text_holder = Editable(spin) ? Text(spin) : Label(spin);
1245     Dimension shadow = SPIN_SHADOW(spin) * 2;
1246     Dimension arrow_width, arrow_height;
1247     /* MotifBc & Resolution Independent */
1248     Dimension height, width;
1249     Arg args[2];
1250     unsigned char unit_type = MUnitType(spin);
1251
1252
1253     /* Resolution Independent */
1254     if (unit_type != XmPIXELS) {
1255         XtSetArg(args[0], XmNunitType, XmPIXELS);
1256         XtSetValues((Widget)spin, args, 1);
1257         XtSetValues(text_holder, args, 1);
1258     }
1259     /* MotifBc */
1260     XtSetArg(args[0], XmNheight, &height);
1261     XtSetArg(args[1], XmNwidth, &width);
1262     XtGetValues(text_holder, args, 2);
1263     /* 
1264      * Find out how big the arrow can be (needed to get 
1265      * width for text_holder).
1266      */
1267     arrow_width = (Dimension)((float)height * ARROW_MULT);
1268     arrow_width = (arrow_width < ARROW_MIN) ? ARROW_MIN : arrow_width;
1269
1270     /* Get height based on arrow width */
1271     arrow_height = arrow_width;
1272     if ((ArrowLayout(spin) == DtARROWS_BEGINNING) ||
1273         (ArrowLayout(spin) == DtARROWS_END))
1274         arrow_height += arrow_height;
1275
1276     /* Make height bigger of 2 - arrows vs text_holder */
1277     if (arrow_height > (Dimension)height)
1278         height = arrow_height;
1279
1280     /* If not stacked add extra width for arrows */
1281     if ((ArrowLayout(spin) != DtARROWS_BEGINNING) &&
1282         (ArrowLayout(spin) != DtARROWS_END)) {
1283         arrow_width += arrow_width;
1284     }
1285
1286     (void)XtMakeResizeRequest((Widget)spin, arrow_width +
1287                               width + shadow +
1288                               (SPIN_MARGIN_W(spin) * 2), 
1289                               height + shadow + (SPIN_MARGIN_H(spin) * 2), 
1290                               NULL, NULL);
1291     OldWidth(spin) = Width(spin);
1292     OldHeight(spin) = Height(spin);
1293
1294     /* Resolution Independent */
1295     if (unit_type != XmPIXELS) { 
1296         XtSetArg(args[0], XmNunitType, unit_type); 
1297         XtSetValues((Widget)spin, args, 1);
1298         XtSetValues(text_holder, args, 1);
1299     } 
1300 }
1301
1302 /*
1303  * This function makes the text_holder (label or text-field) smaller
1304  * if the spin_box couldn't grow to the needed full size.  It will
1305  * also make the text_holder grow if there is space.  The textfield will
1306  * grow with the spin_box, but the label will only grow to its' 
1307  * maximum size.  The label will also shrink down to nothing, but the
1308  * text-field will always keep its' core height.
1309  */
1310 static void
1311 ForceChildSizes(DtSpinBoxWidget spin)
1312 {
1313     Dimension available_height, available_width, arrow_width;
1314     /* MotifBc & Resolution Independent */
1315     Arg args[3];
1316     unsigned char unit_type = XmPIXELS;
1317
1318     /* Resolution Independent */
1319     if (MUnitType(spin) != XmPIXELS) {
1320         unit_type = MUnitType(spin);
1321         XtSetArg(args[0], XmNunitType, XmPIXELS);
1322         XtSetValues(UpArrow(spin), args, 1);
1323         XtSetValues(DownArrow(spin), args, 1);
1324         if (Editable(spin) == False) 
1325                 XtSetValues(Label(spin), args, 1);
1326         else
1327                 XtSetValues(Text(spin), args, 1);
1328     }
1329
1330     CalculateSizes(spin, &available_width, &available_height, &arrow_width);
1331
1332     if (Editable(spin) == FALSE) {  /** label **/
1333         if (available_width > LabelMaxLength(spin))
1334             available_width = LabelMaxLength(spin);
1335
1336         if ((available_width != (Label(spin))->core.width) ||
1337             (available_height != (Label(spin))->core.height))
1338             XtResizeWidget(Label(spin), available_width, available_height,
1339                            (Label(spin))->core.border_width);
1340     }
1341     else if ((Text(spin))->core.width != available_width)  /** TextField **/
1342         XtResizeWidget(Text(spin), available_width,
1343                        (Text(spin))->core.height,
1344                        (Text(spin))->core.border_width);
1345     if ((arrow_width != UpArrow(spin)->core.width) ||
1346         ((UpArrow(spin))->core.height != arrow_width)) {
1347         available_height = (available_height < ARROW_MIN) ? ARROW_MIN : 
1348                             available_height;
1349         XtResizeWidget(UpArrow(spin), arrow_width, arrow_width,
1350                        (UpArrow(spin))->core.border_width);
1351     }
1352     if ((arrow_width != (DownArrow(spin))->core.width) ||
1353         ((DownArrow(spin))->core.height != arrow_width)) {
1354         available_height = (available_height < ARROW_MIN) ? ARROW_MIN : 
1355                             available_height;
1356         XtResizeWidget(DownArrow(spin), arrow_width, arrow_width,
1357                        DownArrow(spin)->core.border_width);
1358     }
1359     /* Resolution Independent */
1360     if (MUnitType(spin) != XmPIXELS) {
1361         XtSetArg(args[0], XmNunitType, unit_type);
1362         XtSetValues(UpArrow(spin), args, 1);
1363         XtSetValues(DownArrow(spin), args, 1);
1364         if (Editable(spin) == False) 
1365                 XtSetValues(Label(spin), args, 1);
1366         else
1367                 XtSetValues(Text(spin), args, 1);
1368     }
1369 }
1370
1371 static void     
1372 CalculateSizes (DtSpinBoxWidget spin,
1373                 Dimension *pwidth,
1374                 Dimension *pheight,
1375                 Dimension *parrow_width)
1376 {
1377     Dimension width, height, arrow_width;
1378
1379     /* Calculate available height for children */
1380     if ((height = spin->core.height - (SPIN_SHADOW(spin) * 2) - 
1381          (SPIN_MARGIN_H(spin) * 2)) <= 0)
1382         height = 1;
1383
1384     /* Get initial available width for children */
1385     width = (spin->core.width - (SPIN_SHADOW(spin) * 2) - 
1386                        (SPIN_MARGIN_W(spin) * 2));
1387
1388     /* label only grows to maximum width needed */
1389     if ((Editable(spin) == FALSE) && 
1390         (height > LabelMaxHeight(spin)))
1391         height = LabelMaxHeight(spin);
1392     else if (Editable(spin)) 
1393         height = (Text(spin))->core.height;
1394     
1395     /* 
1396      * Find out how big the arrow can be (needed to get 
1397      * width for text_holder).
1398      */
1399     arrow_width = (Dimension)(height * ARROW_MULT);
1400     arrow_width = (arrow_width < ARROW_MIN) ? ARROW_MIN : arrow_width;
1401         
1402     /* Make sure width isn't too small or too big */
1403     if ((width -= arrow_width) <= 0)
1404         width = 1;
1405
1406     /* If not stacked subtract extra arrow */
1407     if ((ArrowLayout(spin) != DtARROWS_BEGINNING) &&
1408         (ArrowLayout(spin) != DtARROWS_END)) {
1409         width -= arrow_width;
1410     }
1411
1412     if (pwidth) *pwidth = width;
1413     if (pheight) *pheight = height;
1414     if (parrow_width) *parrow_width = arrow_width;
1415 }
1416
1417 /*
1418  * This function positions the children within the spin_box widget.
1419  * It calls ForceChildSizes() to make sure the children fit within the
1420  * spin_box widget, but it will not try to resize the spin_box widget.
1421  */
1422 static void
1423 LayoutChildren(DtSpinBoxWidget spin)
1424 {
1425     Widget text_holder = Editable(spin) ? Text(spin) : Label(spin);
1426     Position start_x = SPIN_SHADOW(spin) + SPIN_MARGIN_W(spin);
1427     Position start_y = SPIN_SHADOW(spin) + SPIN_MARGIN_H(spin);
1428     Dimension available_height = spin->core.height - (start_y * 2);
1429     Position y, arrow_y;
1430     Dimension arrow_height;
1431     /* Resolution Independent */
1432     Arg args[4];
1433     unsigned char unit_type = XmPIXELS;
1434     
1435     ForceChildSizes(spin);
1436
1437     /* Resolution Independent */
1438     if (MUnitType(spin) != XmPIXELS) {
1439         unit_type = MUnitType(spin);
1440         XtSetArg(args[0], XmNunitType, XmPIXELS);
1441         XtSetValues(UpArrow(spin), args, 1);
1442         XtSetValues(DownArrow(spin), args, 1);
1443         XtSetValues(text_holder, args, 1);
1444     }
1445
1446     /* Center text_holder within spin_box */
1447     y = available_height - text_holder->core.height;
1448     y = ((y < 0) ? 0 : y)/2 + start_y;
1449
1450     arrow_height = (UpArrow(spin))->core.height;
1451     if ((ArrowLayout(spin) == DtARROWS_BEGINNING) ||
1452         (ArrowLayout(spin) == DtARROWS_END))
1453         arrow_height += arrow_height;
1454     arrow_y = available_height - arrow_height;
1455     arrow_y = ((arrow_y < 0) ? 0 : arrow_y)/2 + start_y;
1456
1457     switch (ArrowLayout(spin)) {
1458     case DtARROWS_FLAT_BEGINNING:
1459         XtMoveWidget(UpArrow(spin), start_x, arrow_y);
1460         start_x += (UpArrow(spin))->core.width;
1461         XtMoveWidget(DownArrow(spin), start_x, arrow_y);
1462         start_x += (DownArrow(spin))->core.width;
1463         XtMoveWidget(text_holder, start_x, y);
1464         break;
1465     case DtARROWS_FLAT_END:
1466         XtMoveWidget(text_holder, start_x, y);
1467         /*  
1468          * This start_x places arrow right after text_holder.  With
1469          * labels we want the arrow at the end of the spin_box, so
1470          * the user can use recompute_size more effectively.
1471          * start_x += text_holder->core.width;
1472          */
1473         start_x = (spin->core.width - start_x - 
1474                    (UpArrow(spin))->core.width -
1475                    (DownArrow(spin))->core.width);
1476         XtMoveWidget(UpArrow(spin), start_x, arrow_y);
1477         start_x += (UpArrow(spin))->core.width;
1478         XtMoveWidget(DownArrow(spin), start_x, arrow_y);
1479         break;
1480     case DtARROWS_SPLIT:
1481         XtMoveWidget(DownArrow(spin), start_x, arrow_y);
1482         start_x += (DownArrow(spin))->core.width;
1483         XtMoveWidget(text_holder, start_x, y);
1484         start_x += text_holder->core.width;
1485         XtMoveWidget(UpArrow(spin), start_x, arrow_y);
1486         break;
1487     case DtARROWS_BEGINNING:
1488         XtMoveWidget(UpArrow(spin), start_x, arrow_y);
1489         arrow_y += (UpArrow(spin))->core.height;
1490         XtMoveWidget(DownArrow(spin), start_x, arrow_y);
1491         start_x += (DownArrow(spin))->core.width;
1492         XtMoveWidget(text_holder, start_x, y);
1493         break;
1494     case DtARROWS_END:
1495         XtMoveWidget(text_holder, start_x, y);
1496         /*  
1497          * This start_x places arrow right after text_holder.  With
1498          * labels we want the arrow at the end of the spin_box, so
1499          * the user can use recompute_size more effectively.
1500          * start_x += text_holder->core.width;
1501          */
1502         start_x = spin->core.width - start_x - (UpArrow(spin))->core.width;
1503         XtMoveWidget(UpArrow(spin), start_x, arrow_y);
1504         arrow_y += (UpArrow(spin))->core.width;
1505         XtMoveWidget(DownArrow(spin), start_x, arrow_y);
1506         break;
1507     }
1508     /* Resolution Independent */
1509     if (MUnitType(spin) != XmPIXELS) {
1510         XtSetArg(args[0], XmNunitType, unit_type);
1511         XtSetValues(UpArrow(spin), args, 1);
1512         XtSetValues(DownArrow(spin), args, 1);
1513         XtSetValues(text_holder, args, 1);
1514     }
1515 }
1516
1517
1518 /*
1519  * SetValues() routine for SpinBox widget. Most of the real work
1520  * is done in SetItems() and SetNumeric().  If items is set we store
1521  * our own XmStrings. 
1522  * This function was built with static spin_boxs in mind, meaning that
1523  * is-numeric or editable resources won't be changed constantly.  These
1524  * resources can be changed, but this function doesn't handle them in
1525  * a super-efficient manor.  for example, changing child-type will cause
1526  * the label to be resize even if it isn't managed.
1527  */
1528 static Boolean
1529 SetValues(      DtSpinBoxWidget current,
1530                 DtSpinBoxWidget request,
1531                 DtSpinBoxWidget new)
1532 {
1533     DtSpinBoxPart *new_p = (DtSpinBoxPart*)
1534         &(XmField(new,ipot,DtSpinBox,label,Widget));
1535     DtSpinBoxPart *cur_p = (DtSpinBoxPart*)
1536         &(XmField(current,ipot,DtSpinBox,label,Widget));
1537     Boolean store_info;
1538     char *widget_name;
1539     Boolean label_size_changed = FALSE;
1540     Arg args[20];
1541     int n;
1542     /* Resolution Independent */
1543     unsigned char unit_type = MUnitType(new);
1544
1545     CheckResources(new);
1546
1547     if (Text(new) != Text(current)) {
1548         XtWarning(SB_TEXT);
1549         Text(new) = Text(current);
1550     }
1551
1552     /*
1553      * Editable resource changed.  If the widget (textField or Label)
1554      * doesn't exist, then create it.
1555      */
1556     if (Editable(new) != Editable(current)) {
1557         if (Editable(new)) {
1558             XtUnmanageChild(Label(new));
1559             if (Text(new) == NULL) {
1560                 widget_name = XtMalloc(strlen(XtName((Widget)new)) + 10);
1561                 sprintf(widget_name, "%s_TF", XtName((Widget)new));
1562                 n = 0;
1563                 XtSetArg(args[n], XmNcolumns, TextColumns(new)); n++;
1564                 XtSetArg(args[n], XmNmaxLength, TextMaxLength(new)); n++;
1565                 XtSetArg(args[n], XmNmarginWidth, 2); n++;
1566                 XtSetArg(args[n], XmNmarginHeight, 2); n++;
1567                 if (unit_type != XmPIXELS) {
1568                         XtSetArg(args[n], XmNunitType, XmPIXELS); n++;
1569                 }
1570                 Text(new) = XtCreateManagedWidget(widget_name,
1571                                                     xmTextFieldWidgetClass,
1572                                                     (Widget)new, args, n);
1573                 XtAddCallback(Text(new), XmNlosingFocusCallback, 
1574                               text_losing_focus_cb, (XtPointer)new);
1575                 XtAddCallback(Text(new), XmNactivateCallback, 
1576                               text_activate_cb, (XtPointer)new);
1577                 XtAddCallback(Text(new), XmNfocusCallback, 
1578                               text_focus_cb, (XtPointer)new);
1579                 XtFree(widget_name);
1580                 if (unit_type != XmPIXELS) {
1581                         XtSetArg(args[n], XmNunitType, unit_type); n++;
1582                         XtSetValues(Text(new), args, 1);
1583                 }
1584             }
1585             else
1586                 XtManageChild(Text(new));
1587         }
1588         else {
1589             XtUnmanageChild(Text(new));
1590             if (Label(new) == NULL) {
1591                 widget_name = XtMalloc(strlen(XtName((Widget)new)) + 10);
1592                 sprintf(widget_name, "%s_Label", XtName((Widget)new));
1593                 n = 0;
1594                 XtSetArg(args[n], XmNalignment, Alignment(new)); n++;
1595                 XtSetArg(args[n], XmNrecomputeSize, FALSE); n++;
1596                 XtSetArg(args[n], XmNlabelString, InitLabel); n++;
1597                 XtSetArg(args[n], XmNmarginLeft, LABEL_PADDING); n++;
1598                 XtSetArg(args[n], XmNmarginRight, LABEL_PADDING); n++;
1599                 XtSetArg(args[n], XmNmarginWidth, TEXT_CONTEXT_MARGIN); n++;
1600                 XtSetArg(args[n], XmNmarginHeight, 0); n++;
1601                 if (unit_type != XmPIXELS) {
1602                         XtSetArg(args[n], XmNunitType, XmPIXELS); n++;
1603                 }
1604                 Label(new) = XtCreateManagedWidget(widget_name,
1605                                                      xmLabelWidgetClass,
1606                                                      (Widget)new, args, n);
1607                 XtOverrideTranslations((Widget)Label(new), child_trans);
1608                 XtFree(widget_name);
1609                 if (unit_type != XmPIXELS) { 
1610                         XtSetArg(args[n], XmNunitType, unit_type); n++; 
1611                         XtSetValues(Label(new), args, 1); 
1612                 } 
1613             }
1614             else
1615                 XtManageChild(Label(new));
1616         }
1617         /* 
1618          * Text-fields and labels have different shadows.  Only
1619          * change if user didn't change the shadow resource.
1620          */
1621         if (SPIN_SHADOW(new) == SPIN_SHADOW(current))
1622             SPIN_SHADOW(new) = (Editable(new)) ? TEXT_FIELD_SHADOW :
1623                                                    LABEL_SHADOW;
1624     }
1625
1626     /* Check arrow sensitivity (up arrow is right arrow)*/
1627     if (ArrowSensitivity(new) != ArrowSensitivity(current)) {
1628         XtSetSensitive(UpArrow(new), 
1629                ((ArrowSensitivity(new) == DtARROWS_SENSITIVE) ||
1630                 (ArrowSensitivity(new) == DtARROWS_INCREMENT_SENSITIVE)));
1631         XtSetSensitive(DownArrow(new), 
1632                ((ArrowSensitivity(new) == DtARROWS_SENSITIVE) ||
1633                 (ArrowSensitivity(new) == DtARROWS_DECREMENT_SENSITIVE)));
1634     }
1635
1636     /*
1637      * Check arrow layout.  Only need to change arrows if going to or
1638      * from DtARROWS_SPLIT.  The LayoutChildren() routine actually
1639      * positions the arrows in the correct place.
1640      */
1641     if (ArrowLayout(new) != ArrowLayout(current)) {
1642         if (ArrowLayout(new) == DtARROWS_SPLIT) {
1643             XtSetArg(args[0], XmNarrowDirection, XmARROW_RIGHT);
1644             XtSetValues(UpArrow(new), args, 1);
1645             XtSetArg(args[0], XmNarrowDirection, XmARROW_LEFT);
1646             XtSetValues(DownArrow(new), args, 1);
1647         }
1648         else {
1649             XtSetArg(args[0], XmNarrowDirection, XmARROW_UP);
1650             XtSetValues(UpArrow(new), args, 1);
1651             XtSetArg(args[0], XmNarrowDirection, XmARROW_DOWN);
1652             XtSetValues(DownArrow(new), args, 1);
1653         }
1654     }
1655
1656     if (Text(new) && (Text(new) == Text(current))) {
1657         n = 0;
1658         if (TextColumns(new) != TextColumns(current)) {
1659             XtSetArg(args[n], XmNcolumns, TextColumns(new)); n++;
1660         }
1661         if (TextMaxLength(new) != TextMaxLength(current)) {
1662             XtSetArg(args[n], XmNmaxLength, TextMaxLength(new)); n++;
1663         }
1664         if (n > 0) 
1665             XtSetValues(Text(new), args, n);
1666     }
1667     
1668     /*
1669      * LabelWidget alignment has changed.
1670      */
1671     if (Label(new) && (Alignment(new) != Alignment(current))) {
1672         XtSetArg(args[0], XmNalignment, Alignment(new));
1673         XtSetValues(Label(new), args, 1);
1674     }
1675
1676     store_info = ((Items(new) != Items(current)) ||
1677                   (ItemCount(new) != ItemCount(current)) ||
1678                   (DecimalPoints(new) != DecimalPoints(current)) ||
1679                   (Maximum(new) != Maximum(current)) ||
1680                   (Minimum(new) != Minimum(current)) ||
1681                   (NumericIncrement(new) != NumericIncrement(current)) ||
1682                   ((ChildType(new) == DtNUMERIC) &&
1683                    (Position(new) != Position(current))));
1684     if (store_info)
1685         StoreResourceInfo(new_p, cur_p, (Items(new) != Items(current)));
1686     
1687     if (Label(new) && (store_info || 
1688                          (Label(new) != Label(current)) ||
1689                          (ChildType(new) != ChildType(current)))) {
1690         SetMaximumLabelSize(new_p);
1691         label_size_changed = TRUE;
1692     }
1693     
1694     if (store_info ||
1695         (Alignment(new) != Alignment(current)) ||
1696         (Editable(new) != Editable(current)) ||
1697         (Position(new) != Position(current)) ||
1698         (Label(new) != Label(current)) ||
1699         (ChildType(new) != ChildType(current))) {
1700         if (Editable(new))
1701             SetTextFieldData(new);
1702         else
1703             SetLabelData(new);
1704     }
1705
1706     /*
1707      * Must recalculate the spin_box and re-layout the children.
1708      * If this is not editable, then set the label to its' maximum
1709      * size; it will get chopped if it is too big.  This is needed 
1710      * because we shrink the label down, and SetSpinBoxSize() uses
1711      * the label's core sizes to figure what size to become.
1712      */
1713     if ((Editable(new) != Editable(current)) ||
1714         (SPIN_MARGIN_W(new) != SPIN_MARGIN_W(current)) ||
1715         (SPIN_MARGIN_H(new) != SPIN_MARGIN_H(current)) ||
1716         (SPIN_SHADOW(new) != SPIN_SHADOW(current)) ||
1717         (ArrowLayout(new) != ArrowLayout(current)) ||
1718         (!(Editable(new)) && label_size_changed)) {
1719         ClearShadow(current, TRUE);
1720         if (RecomputeSize(new))
1721             SetSpinBoxSize(new);
1722         LayoutChildren(new);
1723         DrawShadow(new);
1724     }
1725     n=0;
1726     if(CBgPixel(new) != CBgPixel(current))
1727     {
1728         XtSetArg(args[n],XmNbackground,CBgPixel(new));n++;
1729     }
1730     if(CBgPixmap(new) != CBgPixmap(current))
1731     {
1732         XtSetArg(args[n],XmNbackgroundPixmap,CBgPixmap(new));n++;
1733     }
1734     if(MFgPixel(new) != MFgPixel(current))
1735     {
1736         XtSetArg(args[n],XmNforeground,MFgPixel(new));n++;
1737     }
1738     if(Text(new))
1739         XtSetValues (Text(new),args,n);
1740     if(Label(new))
1741         XtSetValues (Label(new),args,n);
1742     if(UpArrow(new))
1743         XtSetValues (UpArrow(new),args,n);
1744     if(DownArrow(new))
1745         XtSetValues (DownArrow(new),args,n);
1746     
1747     return(FALSE);
1748 }
1749
1750
1751 /*
1752  * This function clears the shadow around our widget.  If all is TRUE,
1753  * then clear all 4 sides; otherwise, only clear the right and bottom
1754  * sides (during resize). 
1755  */ 
1756 static void
1757 ClearShadow(    DtSpinBoxWidget w,
1758                 Boolean all)
1759 {
1760     Dimension shadow = SPIN_SHADOW(w);
1761     Dimension margin_w = SPIN_MARGIN_W(w);
1762     Dimension margin_h = SPIN_MARGIN_H(w);
1763
1764     if ((shadow > 0) && XtIsRealized((Widget)w)) {
1765         if (all) {
1766             XClearArea(XtDisplayOfObject((Widget)w),
1767                        XtWindowOfObject((Widget)w), 
1768                        margin_w, margin_h,
1769                        OldWidth(w) - (margin_w * 2),
1770                        shadow, FALSE);
1771             XClearArea(XtDisplayOfObject((Widget)w),
1772                        XtWindowOfObject((Widget)w), 
1773                        margin_w, margin_h, shadow, 
1774                        OldHeight(w) - (margin_h * 2), FALSE);
1775         }
1776         XClearArea(XtDisplayOfObject((Widget)w), XtWindowOfObject((Widget)w),
1777                    margin_w, OldHeight(w) - margin_h - shadow,
1778                    OldWidth(w) - (margin_w * 2), shadow, FALSE);
1779         XClearArea(XtDisplayOfObject((Widget)w), XtWindowOfObject((Widget)w),
1780                    OldWidth(w) - margin_w - shadow,
1781                    margin_h, shadow, 
1782                    OldHeight(w) - (margin_h * 2), FALSE);
1783     }
1784     DrawHighlight(w, TRUE);
1785 }
1786
1787 /* 
1788  * This functions draws the shadow around our spin_box.
1789  */
1790 static void
1791 DrawShadow(DtSpinBoxWidget w)
1792 {
1793     Dimension shadow = SPIN_SHADOW(w);
1794     Dimension margin_w = SPIN_MARGIN_W(w);
1795     Dimension margin_h = SPIN_MARGIN_H(w);
1796     
1797     if ((shadow > 0) && XtIsRealized((Widget)w)) {
1798         XmeDrawShadows(XtDisplayOfObject((Widget)w),
1799                        XtWindowOfObject((Widget)w),
1800                        w->manager.top_shadow_GC,
1801                        w->manager.bottom_shadow_GC, 
1802                        margin_w, margin_h,
1803                        w->core.width - (margin_w * 2),
1804                        w->core.height - (margin_h * 2),
1805                        shadow, XmSHADOW_OUT);
1806     }
1807     DrawHighlight(w, FALSE);
1808 }
1809
1810 /*
1811  * This function sets up the items information for the SpinBox, as
1812  * well as variables needed for child_type.
1813  */
1814 static void
1815 StoreResourceInfo(      DtSpinBoxPart *spin_p,
1816                         DtSpinBoxPart *old_p,
1817                         Boolean do_items)
1818 {
1819     XmStringTable table;
1820     int i, base = 1;
1821
1822     if (do_items && spin_p->items) {
1823         /* Free up current items if needed */
1824         if (old_p && old_p->items) {
1825             for (i = 0; i < old_p->item_count; i++) {
1826                 XmStringFree(old_p->items[i]);
1827             }
1828             XtFree((char*)old_p->items);
1829         }
1830             
1831         /*
1832          * Loop through all the items, copy them into our space.
1833          */
1834         table = (XmStringTable)XtMalloc(sizeof(XmString) * spin_p->item_count);
1835         for (i = 0; i < spin_p->item_count; i++) {
1836             table[i] = XmStringCopy(spin_p->items[i]);
1837         }
1838         spin_p->items = table;
1839         for (i = 0; i < spin_p->item_count; i++)
1840             spin_p->items[i] = table[i];
1841     }
1842
1843     /*
1844      * Store the numeric information
1845      */
1846
1847     /* get base number for convert ints to floats */
1848     for (i = 0; i < spin_p->decimal_points; i++)
1849         base *= 10;
1850
1851     /* Set new initial values */
1852     spin_p->min = (float)spin_p->minimum/base;
1853     spin_p->max = (float)spin_p->maximum/base;
1854     spin_p->increment = (float)spin_p->numeric_increment/base;
1855
1856     spin_p->current = (float)spin_p->position/base;
1857
1858     /* Create format string used to build correct XmString value */
1859     spin_p->float_format[0] = '%';
1860     sprintf((char*)(spin_p->float_format+1), ".%df", spin_p->decimal_points);
1861 }
1862
1863
1864 /* Caller must free string */
1865 static char*
1866 GetTextString(XmString xm_string)
1867 {
1868     XmStringContext context;
1869     XmStringComponentType type;
1870     XmStringCharSet charset;
1871     XmStringDirection direction;
1872     XmStringComponentType unknown_tag;
1873     unsigned short ul;
1874     unsigned char *uv;
1875     char *text = NULL;
1876     Boolean done = FALSE;
1877
1878     XmStringInitContext(&context, xm_string);
1879     
1880     /* Loop until 1st char* found */
1881     while (!done) {
1882         type = XmStringGetNextComponent(context, &text, &charset,
1883                                         &direction, &unknown_tag, 
1884                                         &ul, &uv);
1885         switch (type) {
1886         case XmSTRING_COMPONENT_END:
1887             done = TRUE;
1888             break;
1889         case XmSTRING_COMPONENT_TEXT:
1890         case XmSTRING_COMPONENT_LOCALE_TEXT:
1891             done = TRUE;
1892             break;
1893         default:
1894             break;
1895         }
1896     }
1897     XmStringFreeContext(context);
1898     return(text);
1899 }
1900
1901 /*
1902  * Take the string out of the list and put it into the text-field.
1903  * text-fields don't handle xm-strings, so we must get the char*
1904  * out of it (only getting the first segment).  This is slower than
1905  * storing the text-strings (char*) ourselves, but that would take
1906  * up a lot of memory.  Since this setting happens during a user
1907  * action, speed isn't a problem.
1908  */
1909 static void
1910 SetTextFieldData(DtSpinBoxWidget spin)
1911 {
1912     char string[NUMERIC_LENGTH];
1913     XmString xm_string;
1914     char *text;
1915     Arg arg;
1916     
1917     
1918     if (ChildType(spin) == DtNUMERIC) {
1919         sprintf(string, FloatFormat(spin), (float)(Current(spin)));
1920         XtSetArg(arg, XmNvalue, string);
1921         XtSetValues(Text(spin), &arg, 1);
1922     }
1923     else {
1924         if (ItemCount(spin) == 0){
1925             XtSetArg(arg, XmNvalue, "");
1926             XtSetValues(Text(spin), &arg, 1);
1927             return;
1928         }
1929         else {
1930             xm_string = (Items(spin))[Position(spin)];
1931             if ((text = GetTextString(xm_string))) {
1932                 XtSetArg(arg, XmNvalue, text);
1933                 XtSetValues(Text(spin), &arg, 1);
1934                 XtFree(text);
1935             }
1936         }
1937     }
1938 }
1939
1940 /*
1941  * Set the maximum size of the label, depending on the
1942  * characteristics of the list of items.  Not very efficient
1943  * if switching from numeric to non-numeric.
1944  */
1945 static void
1946 SetMaximumLabelSize(DtSpinBoxPart *spin_p)
1947 {
1948     XmString xm_string;
1949     XmFontList font_list;
1950     char string[NUMERIC_LENGTH];
1951     Dimension width, height;
1952     Dimension longest = 0;
1953     Dimension highest = 0;
1954     Arg args[5];
1955     int i;
1956     /* Resolution Independent */
1957     unsigned char unit_type;
1958     
1959     /* Get font info from the widget */
1960     XtSetArg(args[0], XmNfontList, &font_list);
1961     XtSetArg(args[1], XmNunitType, &unit_type); /* resolution Independent */
1962     XtGetValues(spin_p->label, args, 2);
1963     if ( unit_type != XmPIXELS) {
1964         XtSetArg(args[0], XmNunitType, XmPIXELS);
1965         XtSetValues(spin_p->label, args, 1);
1966     }
1967
1968     if (spin_p->child_type == DtNUMERIC) {
1969         /* Find out maximum size of the widget from min/max */
1970         sprintf(string, spin_p->float_format, spin_p->min);
1971         xm_string = XmStringCreateLocalized(string);
1972         XmStringExtent(font_list, xm_string, &longest, &highest);
1973         XmStringFree(xm_string);
1974         sprintf(string, spin_p->float_format, spin_p->max);
1975         xm_string = XmStringCreateLocalized(string);
1976         XmStringExtent(font_list, xm_string, &width, &height);
1977         XmStringFree(xm_string);
1978         
1979         longest = (width > longest) ? width : longest;
1980         highest = (height > highest) ? height : highest;
1981     }
1982     else if (spin_p->items) {
1983         /*
1984          * Loop through all the items to find the biggest dimensions
1985          */
1986         for (i = 0; i < spin_p->item_count; i++) {
1987             XmStringExtent(font_list, spin_p->items[i], &width, &height);
1988             longest = (width > longest) ? width : longest;
1989             highest = (height > highest) ? height : highest;
1990         }
1991     }
1992     else {
1993         XmStringExtent(font_list, InitLabel, &longest, &highest);
1994     }
1995
1996     spin_p->label_max_length = 
1997         ( (Dimension)(longest + ( (LABEL_PADDING + TEXT_CONTEXT_MARGIN) *2) ) >
1998           (Dimension)Width(spin_p->label) ) ? 
1999         (longest + ((LABEL_PADDING+TEXT_CONTEXT_MARGIN) * 2)) :
2000         Width(spin_p->label);
2001
2002     spin_p->label_max_height = highest > Height(spin_p->label) ?
2003         highest : Height(spin_p->label);
2004     XtResizeWidget(spin_p->label, spin_p->label_max_length, 
2005                    spin_p->label_max_height,
2006                    spin_p->label->core.border_width);
2007
2008     /* Resolution Independent */
2009     if ( unit_type != XmPIXELS) {
2010         XtSetArg(args[0], XmNunitType, unit_type);
2011         XtSetValues(spin_p->label, args, 1);
2012     }
2013 }
2014
2015
2016 /*
2017  * Put the current list item into the label.
2018  */
2019 static void
2020 SetLabelData(DtSpinBoxWidget spin)
2021 {
2022     XmString xm_string;
2023     char string[NUMERIC_LENGTH];
2024     int index = Position(spin);
2025     Arg arg;
2026
2027     if (ChildType(spin) == DtNUMERIC) {
2028         sprintf(string, FloatFormat(spin), (float)Current(spin));
2029         xm_string = XmStringCreateLocalized(string);
2030         XtSetArg(arg, XmNlabelString, xm_string);
2031         XtSetValues(Label(spin), &arg, 1);
2032     }
2033     else {
2034         /*
2035          * If the item is not empty, get the current item from the list, else
2036          * use InitLabel.
2037          */
2038         xm_string = (ItemCount(spin)>0) ? (Items(spin))[index] : InitLabel;
2039         XtSetArg(arg, XmNlabelString, xm_string);
2040         XtSetValues(Label(spin), &arg, 1);
2041     }
2042 }
2043
2044 /*
2045  * Timout dispatch routine.  This calls the appropriate callback function
2046  * to simulate up or down arrow activation.
2047  */
2048 static void
2049 timer_dispatch( XtPointer client_data,
2050                 XtIntervalId *id)
2051 {
2052     DtSpinBoxWidget spin_w = (DtSpinBoxWidget)client_data;
2053
2054     Timer(spin_w) = (XtIntervalId)NULL;
2055     InitCb(spin_w) = FALSE;
2056     if (WhichArrow(spin_w) == XmARROW_UP) {
2057         if (Grabbed(spin_w)) {
2058             XtRemoveGrab(UpArrow(spin_w));
2059             Grabbed(spin_w) = FALSE;
2060         }
2061         up_cb(NULL, client_data, NULL);
2062     }
2063     else {
2064         if (Grabbed(spin_w)) {
2065             XtRemoveGrab(DownArrow(spin_w));
2066             Grabbed(spin_w) = FALSE;
2067         }
2068         down_cb(NULL, client_data, NULL);
2069     }
2070 }
2071
2072 static void
2073 TextFieldActivate(DtSpinBoxPart *spin_p)
2074 {
2075     XmTextFieldWidget w = (XmTextFieldWidget)(spin_p->text);
2076     XmAnyCallbackStruct cb;
2077     char string[NUMERIC_LENGTH];
2078     char *data = NULL;
2079     char *text = NULL;
2080     Arg arg;
2081     Boolean free_me = TRUE;
2082     
2083     XtSetArg(arg, XmNvalue, &data);
2084     XtGetValues((Widget)w, &arg, 1);
2085
2086     if (spin_p->child_type == DtNUMERIC) {
2087         sprintf(string, spin_p->float_format, (float)spin_p->current);
2088         text = string;
2089         free_me = FALSE;
2090     }
2091     else if (spin_p->items)
2092         text = GetTextString(spin_p->items[spin_p->position]);
2093
2094     if (text && data && (strcmp(text, data) == 0)) {
2095         if (free_me)
2096             XtFree(text);
2097         return;
2098     }
2099     /* Only send callback if both are not NULL */
2100     else if (!((text == NULL) && (data == NULL))) {
2101         cb.reason = XmCR_ACTIVATE;
2102         cb.event  = NULL;
2103         /* MotifBc */
2104         if (XtHasCallbacks((Widget)w, XmNactivateCallback)==XtCallbackHasSome)
2105                XtCallCallbacks((Widget)w, XmNactivateCallback, 
2106                                (XtPointer) &cb);
2107         if (text && free_me)
2108             XtFree(text);
2109     }
2110 }
2111
2112 /*
2113  * This function calls the appropriate callback for the spin_box.
2114  * It gathers the correct arguments and fills in the callback structure.
2115  */
2116 static Boolean
2117 SendCallback(   DtSpinBoxWidget spin,
2118                 XEvent *event,
2119                 Boolean value_changed,
2120                 int position,
2121                 float current, /* Used for numeric */
2122                 Boolean crossed)
2123 {
2124     DtSpinBoxCallbackStruct cb;
2125     XmString xm_string = NULL;
2126     char string[NUMERIC_LENGTH];
2127
2128     if (ChildType(spin) == DtNUMERIC) {
2129         sprintf(string, FloatFormat(spin), (float)current);
2130         xm_string = XmStringCreateLocalized(string);
2131     }
2132     else {
2133         xm_string = (ItemCount(spin)>0) ? (Items(spin))[position] : InitLabel;
2134         xm_string = XmStringCopy(xm_string);
2135     }
2136
2137     if (event)
2138         cb.reason = DtCR_OK;
2139     else if (WhichArrow(spin) == XmARROW_UP)
2140         cb.reason = DtCR_SPIN_NEXT;
2141     else
2142         cb.reason = DtCR_SPIN_PRIOR;
2143     cb.doit = TRUE;
2144     cb.event = event;
2145     cb.widget = (Widget)spin;
2146     cb.position = position;
2147     cb.value = xm_string;
2148     cb.crossed_boundary = crossed;
2149     if (value_changed) {
2150         XtCallCallbackList((Widget)spin, ValueChangedCallback(spin), 
2151                            (XtPointer)&cb);
2152         cb.doit = TRUE;
2153     }
2154     else {
2155         XtCallCallbackList((Widget)spin, ModifyVerifyCallback(spin), 
2156                            (XtPointer)&cb);
2157     }
2158     XmStringFree(xm_string);
2159
2160     return(cb.doit);
2161 }
2162
2163
2164 /*
2165  * This function gets called by the up/down arm callback functions.
2166  * We set up the timer and send the modify-verify and value-changed
2167  * callbacks. 
2168  * There are potential problems if the user does some weird stuff 
2169  * in the callbacks.  I have added protection against the case where
2170  * a user does a grab (with XtAddGrab/XtPopup/etc.) in the callbacks.
2171  * Grabbing in the callback would cause us to lose the button-release
2172  * (disarm), which would make the timer go on forever.  A grab is
2173  * done after the callbacks just to make sure we will receive the
2174  * button-release.  The button-release will call disarm_cb() which will
2175  * un-grab and disable the timer.  I have also added a leave callback
2176  * which helps to protect against these kinds of problems.  
2177  * If the callback goes into another event-loop (which I hope would
2178  * never happen), we would spin continuously (since our XtAddGrab never
2179  * get called), until the user left the window (which would call 
2180  * grab_leave_cb).  The grabbed flag gets set if we do the grab, so that
2181  * we know if we can remove the grab.  Our XtAddGrab() might not get called
2182  * if the callback enters another event-loop.
2183  *
2184  * The event sent in the callback will be NULL during continuous spinning.
2185  */
2186 static void
2187 FinishUpDown(   DtSpinBoxWidget spin,
2188                 XtPointer arrow_call_data,
2189                 int new_position,
2190                 float new_current,
2191                 Boolean crossed)
2192 {
2193     XmArrowButtonCallbackStruct *arrow_data;
2194     XEvent *last_event = NULL;
2195     int repeat_delay = RepeatDelay(spin);
2196
2197     if (InitCb(spin))    
2198         repeat_delay = InitialDelay(spin);
2199     Timer(spin) = XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)spin),
2200                             repeat_delay, timer_dispatch, (XtPointer)spin);
2201
2202     /* Try to get Xevent */
2203     if ((arrow_data = (XmArrowButtonCallbackStruct*)arrow_call_data))
2204         last_event = arrow_data->event;
2205
2206     /* 
2207      * Send modify_verify callback.  If user says no, then
2208      * clear the timer and reset the state before returning.
2209      */
2210     if (SendCallback(spin, last_event, FALSE, new_position,
2211                      new_current, crossed) == FALSE) {
2212         XtRemoveTimeOut(Timer(spin));
2213         Timer(spin) = (XtIntervalId)NULL;
2214         InitCb(spin) = TRUE;
2215         return;
2216     }
2217
2218     /* User said yes, so set widget values */
2219     Position(spin) = new_position;
2220     Current(spin) = new_current;
2221     if (Editable(spin))
2222         SetTextFieldData(spin);
2223     else
2224         SetLabelData(spin);
2225
2226     /* send value_changed callback */
2227     (void)SendCallback(spin, last_event, TRUE, Position(spin),
2228                        Current(spin), crossed);
2229
2230     /* See notes at top of function on XtAddGrab usage */
2231     Grabbed(spin) = TRUE;
2232     if (WhichArrow(spin) == XmARROW_UP)
2233         XtAddGrab(UpArrow(spin), FALSE, FALSE);
2234     else
2235         XtAddGrab(DownArrow(spin), FALSE, FALSE);
2236 }
2237
2238 /*
2239  * Show the next value in the SpinBox.  If numeric, just add the
2240  * increment value.  If using string-table, get the next one in the
2241  * table.  This function takes care of wrap around.  Set the arrow
2242  * type.  This is needed for the timer_dispatch function.  up_cb
2243  * gets called the first time the button is pressed, and each time the
2244  * timer goes off.
2245  * All widget internals are expected to be correct here; they
2246  * get verified when set by the user.
2247  */
2248 static void
2249 up_cb(  Widget w,
2250         XtPointer client_data,
2251         XtPointer call_data)
2252 {
2253     DtSpinBoxWidget spin = (DtSpinBoxWidget)client_data;
2254     DtSpinBoxPart *spin_p = (DtSpinBoxPart*)
2255         &(XmField(spin,ipot,DtSpinBox,label,Widget));
2256     Boolean crossed_boundary = FALSE;
2257     int new_position = Position(spin);
2258     float new_current = Current(spin);
2259
2260    /* Getting Focus */
2261     if ( !_XmFocusIsHere( (Widget)spin) )
2262         XmProcessTraversal((Widget)spin,
2263                           (XmTraversalDirection) XmTRAVERSE_CURRENT);
2264
2265     if (Editable(spin))
2266         TextFieldActivate(spin_p);
2267
2268     /*
2269      * If non-numeric and no items then ignore the user activate event.
2270      */
2271     if ((ChildType(spin) == DtSTRING) && (ItemCount(spin) == 0))
2272         return;
2273     
2274     if (ChildType(spin) == DtNUMERIC) {
2275         if ((new_current + Increment(spin)) > Max(spin)) {
2276             if (Wrap(spin)) {
2277                 new_position = Minimum(spin);
2278                 new_current = Min(spin);
2279                 crossed_boundary = TRUE;
2280             }
2281             else
2282                 XBell(XtDisplayOfObject((Widget)spin), 0);
2283         }
2284         else {
2285             new_position += NumericIncrement(spin);
2286             new_current += Increment(spin);
2287         }
2288     }
2289     else if (ItemCount(spin) >0) {
2290         if (new_position == (ItemCount(spin) - 1)) {
2291             if (Wrap(spin)) {
2292                 new_position = 0;
2293                 crossed_boundary = TRUE;
2294             }
2295             else
2296                 XBell(XtDisplayOfObject((Widget)spin), 0);
2297         }
2298         else
2299             new_position++;
2300     }
2301
2302     WhichArrow(spin) = XmARROW_UP;
2303     FinishUpDown(spin, call_data, new_position, new_current, crossed_boundary);
2304 }
2305
2306
2307 /*
2308  * Show the previous value in the SpinBox.  If numeric, just decrement
2309  * the increment value.  If using string-table, get the previous one in the
2310  * table.  This function takes care of wrap around. Set the arrow
2311  * type.  This is needed for the timer_dispatch function.  down_cb
2312  * gets called the first time the button is pressed, and each time the
2313  * timer goes off.
2314  * All widget internals are expected to be correct here; they
2315  * get verified when set by the user.
2316  */
2317 static void
2318 down_cb(Widget w,
2319         XtPointer client_data,
2320         XtPointer call_data)
2321 {
2322     DtSpinBoxWidget spin = (DtSpinBoxWidget)client_data;
2323     DtSpinBoxPart *spin_p = (DtSpinBoxPart*)
2324         &(XmField(spin,ipot,DtSpinBox,label,Widget));
2325     Boolean crossed_boundary = FALSE;
2326     int new_position = Position(spin);
2327     float new_current = Current(spin);
2328     
2329    /* #5: Getting Focus */
2330     if ( !_XmFocusIsHere( (Widget)spin) )
2331       XmProcessTraversal((Widget)spin,
2332                          (XmTraversalDirection) XmTRAVERSE_CURRENT);
2333
2334     if (Editable(spin))
2335         TextFieldActivate(spin_p);
2336
2337     /*
2338      * If non-numeric and no items then ignore the user activate event.
2339      */
2340     if ((ChildType(spin) == DtSTRING) && (ItemCount(spin) == 0))
2341         return;
2342
2343     if (ChildType(spin) == DtNUMERIC) {
2344         if ((new_current - Increment(spin)) < Min(spin)) {
2345             if (Wrap(spin)) {
2346                 new_current = Max(spin);
2347                 new_position = Maximum(spin);
2348                 crossed_boundary = TRUE;
2349             }
2350             else
2351                 XBell(XtDisplayOfObject((Widget)spin), 0);
2352         }
2353         else {
2354             new_current -= Increment(spin);
2355             new_position -= NumericIncrement(spin);
2356         }
2357     }
2358     else if (ItemCount(spin)>0) {
2359         if (new_position == 0) {
2360             if (Wrap(spin)) {
2361                 new_position = ItemCount(spin) - 1;
2362                 crossed_boundary = TRUE;
2363             }
2364             else
2365                 XBell(XtDisplayOfObject((Widget)spin), 0);
2366         }
2367         else
2368             new_position--;
2369     }
2370
2371     WhichArrow(spin) = XmARROW_DOWN;
2372     FinishUpDown(spin, call_data, new_position, new_current, crossed_boundary);
2373 }
2374
2375 static void
2376 disarm_cb(      Widget w,
2377                 XtPointer client_data,
2378                 XtPointer call_data)
2379 {
2380     DtSpinBoxWidget spin = (DtSpinBoxWidget)client_data;
2381
2382     if ((int)Timer(spin)) {
2383         InitCb(spin) = TRUE;
2384         XtRemoveTimeOut(Timer(spin));
2385         Timer(spin) = (XtIntervalId)NULL;
2386         if (Grabbed(spin)) {
2387             XtRemoveGrab(w);
2388             Grabbed(spin) = FALSE;
2389         }
2390     }
2391 }
2392
2393 static void
2394 grab_leave_cb(  Widget w,
2395                 XtPointer client_data,
2396                 XEvent *event,
2397                 Boolean *dispatch)
2398 {
2399     DtSpinBoxWidget spin = (DtSpinBoxWidget)client_data;
2400
2401     if ((int)Timer(spin) && 
2402         ((event->xcrossing.mode == NotifyGrab) ||
2403          (event->xcrossing.mode == NotifyUngrab) ||
2404          (!(event->xcrossing.state & Button1Mask)))) {
2405         InitCb(spin) = TRUE;
2406         XtRemoveTimeOut(Timer(spin));
2407         Timer(spin) = (XtIntervalId)NULL;
2408         if (Grabbed(spin)) {
2409             XtRemoveGrab(w);
2410             Grabbed(spin) = FALSE;
2411         }
2412     }
2413 }
2414
2415 /*
2416  * We get the text-field losing-focus callback, so pass it on to
2417  * the user if they requested it.  Our losing-focus callback 
2418  * is just a convenience callback, so that the user doesn't
2419  * have to get the text-field first.  This make our integration
2420  * with XDesigner a little easier.
2421  */
2422 static void
2423 text_losing_focus_cb(   Widget w,
2424                         XtPointer client_data,
2425                         XtPointer call_data)
2426 {
2427     DtSpinBoxWidget spin = (DtSpinBoxWidget)client_data;
2428
2429     if (LosingFocusCallback(spin))
2430         XtCallCallbackList((Widget)spin, 
2431                            LosingFocusCallback(spin), 
2432                            (XtPointer)call_data);
2433 }
2434
2435 /*
2436  * We get the text-field activate callback, so pass it on to
2437  * the user if they requested it.  Our activate callback 
2438  * is just a convenience callback, so that the user doesn't
2439  * have to get the text-field first.  This make our integration
2440  * with XDesigner a little easier.
2441  */
2442 static void
2443 text_activate_cb(Widget w,
2444                 XtPointer client_data,
2445                 XtPointer call_data)
2446 {
2447     DtSpinBoxWidget spin = (DtSpinBoxWidget)client_data;
2448     
2449     if (ActivateCallback(spin))
2450         XtCallCallbackList((Widget)spin, 
2451                            ActivateCallback(spin), 
2452                            (XtPointer)call_data);
2453 }
2454
2455 /*
2456  * We get the text-field focus callback, so pass it on to
2457  * the user if they requested it.  Our focus callback 
2458  * is just a convenience callback, so that the user doesn't
2459  * have to get the text-field first.  This make our integration
2460  * with XDesigner a little easier.
2461  */
2462 static void
2463 text_focus_cb(  Widget w,
2464                 XtPointer client_data,
2465                 XtPointer call_data)
2466 {
2467     DtSpinBoxWidget spin = (DtSpinBoxWidget)client_data;
2468
2469     if (FocusCallback(spin))
2470         XtCallCallbackList((Widget)spin, 
2471                            FocusCallback(spin), 
2472                            (XtPointer)call_data);
2473 }
2474
2475
2476 /*
2477  * Synthetic resource get functions.
2478  */
2479
2480 static XmImportOperator
2481 _XmSetSyntheticResForChild(     Widget widget,
2482                                 int offset,
2483                                 XtArgVal * value)
2484
2485     return(XmSYNTHETIC_LOAD);
2486 }
2487
2488 void
2489 _DtSpinBoxGetArrowSize( Widget w,
2490                                 int resource_offset,
2491                                 XtArgVal *value)
2492 {
2493     DtSpinBoxWidget spin = (DtSpinBoxWidget)w;
2494     Dimension data;
2495     Arg arg;
2496
2497     /* MotifBc */
2498     XtSetArg(arg, XmNheight, &data);
2499     XtGetValues(UpArrow(spin), &arg, 1);
2500     *value = (XtArgVal)data;
2501 }
2502
2503 /*
2504  * Routines which manipulate the SpinBox list.  These are external
2505  * for use by users of our widget.
2506  */
2507
2508 Widget 
2509 DtCreateSpinBox(        Widget parent,
2510                         char *name,
2511                         Arg *arglist,
2512                         Cardinal num_args)
2513 {
2514     return(XtCreateWidget(name, dtSpinBoxWidgetClass, parent,
2515                           arglist, num_args));
2516 }
2517
2518 void
2519 DtSpinBoxAddItem(       Widget spinw,
2520                         XmString item,
2521                         int pos)
2522 {
2523     DtSpinBoxWidget spin = (DtSpinBoxWidget)spinw;
2524     DtSpinBoxPart *spin_p;
2525     XmString old, new_str, tmp;
2526     int total_items;
2527     _DtWidgetToAppContext(spinw);
2528     _DtAppLock(app);
2529
2530     spin_p = (DtSpinBoxPart*) &(XmField(spin,ipot,DtSpinBox,label,Widget));
2531
2532     total_items = ItemCount(spin) + 1;
2533     Items(spin) = (XmString *)XtRealloc((char*)Items(spin), 
2534                                           (sizeof(XmString) * total_items));
2535     new_str = XmStringCopy(item);
2536
2537     pos--;  /* User gives pos starting at 1 (0 means end of list) */
2538
2539     if ((pos < 0) || (pos > ItemCount(spin)))
2540         pos = ItemCount(spin);
2541
2542     if (pos >= ItemCount(spin))
2543         (Items(spin))[pos] = new_str;
2544     else {
2545         old = (Items(spin))[pos];
2546         (Items(spin))[pos] = new_str;
2547         for (pos++; pos < total_items; pos++) {
2548             tmp = (Items(spin))[pos];
2549             (Items(spin))[pos] = old;
2550             old = tmp;
2551         }
2552     }
2553     ItemCount(spin) = total_items;
2554
2555     if (Label(spin)) {
2556         SetMaximumLabelSize(spin_p);
2557         if (Editable(spin) == FALSE) {
2558             ClearShadow(spin, TRUE);
2559             if (RecomputeSize(spin))
2560                 SetSpinBoxSize(spin);
2561             LayoutChildren(spin);
2562             DrawShadow(spin);
2563         }
2564     }
2565
2566     /* Update the text-field or label */
2567     if (Editable(spin))
2568         SetTextFieldData(spin);
2569     else
2570         SetLabelData(spin);
2571
2572     _DtAppUnlock(app);
2573 }
2574
2575
2576
2577 void
2578 DtSpinBoxDeletePos(     Widget spinw,
2579                         int pos)
2580 {
2581     DtSpinBoxWidget spin = (DtSpinBoxWidget)spinw;
2582     DtSpinBoxPart *spin_p;
2583     int total_items;
2584     _DtWidgetToAppContext(spinw);
2585     _DtAppLock(app);
2586
2587     if (ItemCount(spin) < 1)
2588       {
2589         _DtAppUnlock(app);
2590         return;
2591       }
2592
2593     spin_p = (DtSpinBoxPart*) &(XmField(spin,ipot,DtSpinBox,label,Widget));
2594
2595     pos--;
2596     if ((pos < 0) || (pos > ItemCount(spin)))
2597         pos = ItemCount(spin) - 1;
2598
2599     total_items = ItemCount(spin) - 1;
2600     XmStringFree((Items(spin))[pos]);
2601
2602     /* To keep Position of SpinBox up to date */
2603     if (Position(spin) > 0 && 
2604         ((Position(spin) >= total_items) || pos < Position(spin)) )
2605         Position(spin) = Position(spin) - 1;
2606
2607     if (pos < ItemCount(spin)) {
2608         for (; pos < total_items; pos++)
2609             (Items(spin))[pos] = (Items(spin))[pos+1];
2610     }
2611     if (total_items > 0)
2612         Items(spin) = (XmString *)XtRealloc((char*)Items(spin),
2613                                           (sizeof(XmString) * total_items));
2614     else {
2615         XtFree((char *)Items(spin));
2616         Items(spin) = (XmString *)NULL;
2617     }
2618     ItemCount(spin) = total_items;
2619
2620     if (Label(spin)) {
2621         SetMaximumLabelSize(spin_p);
2622         if (Editable(spin) == FALSE) {
2623             ClearShadow(spin, TRUE);
2624             if (RecomputeSize(spin))
2625                 SetSpinBoxSize(spin);
2626             LayoutChildren(spin);
2627             DrawShadow(spin);
2628         }
2629     }
2630
2631     /* Update the text-field or label */
2632     if (Editable(spin))
2633         SetTextFieldData(spin);
2634     else
2635         SetLabelData(spin);
2636
2637     _DtAppUnlock(app);
2638 }
2639
2640 /*
2641  * Make the given item the currently visible item in the
2642  * text-field or label.
2643  */
2644 void
2645 DtSpinBoxSetItem(       Widget spinw,
2646                         XmString item)
2647 {
2648     DtSpinBoxWidget spin = (DtSpinBoxWidget)spinw;
2649     int i;
2650     _DtWidgetToAppContext(spinw);
2651     _DtAppLock(app);
2652
2653     if (item && ItemCount(spin)>0) {
2654         for (i = 0; i < ItemCount(spin); i++)
2655             if (XmStringCompare(item, (Items(spin))[i]))
2656                 break;
2657         if (i < ItemCount(spin)) {
2658             Position(spin) = i;
2659             if (Editable(spin))
2660                 SetTextFieldData(spin);
2661             else
2662                 SetLabelData(spin);
2663         }
2664         else
2665             XtWarning(SB_SET_ITEM);
2666     }
2667     else
2668         XtWarning(SB_SET_ITEM);
2669
2670     _DtAppUnlock(app);
2671 }