2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: SpinBox.c /main/9 1996/10/29 12:49:58 cde-hp $
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.
34 /***********************************************************
35 Copyright 1993 Interleaf, Inc.
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.
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 ******************************************************************/
51 * (C) Copyright 1991,1992, 1993
56 * SpinBox.c (DtSpinBoxWidget):
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.
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.
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.
74 * Make some of the SpinBox functions common, so they can be shared
78 * Changing margin_width or margin_height resources when the
79 * spin_box has focus will probably result in display glitches.
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".
86 * For a description of the Motif widget binary compatibility mechanism
87 * see the reference manual entry on XmResolveAllPartOffsets().
91 #include <Dt/DtMsgsP.h>
94 #include <Xm/RepType.h>
96 #include "DtWidgetI.h"
98 #include <Xm/XmPrivate.h> /* _XmShellIsExclusive */
101 #include <langinfo.h>
108 #define DtSpinBoxIndex (XmManagerIndex + 1)
109 static XmOffsetPtr ipot; /* Instance part offset table */
110 static XmOffsetPtr cpot; /* Constraint part offset table */
112 static void ClassInitialize ();
113 static void Initialize (DtSpinBoxWidget request,
114 DtSpinBoxWidget new, ArgList given_args,
116 static XmNavigability WidgetNavigable (DtSpinBoxWidget spin);
117 static void _SpinBoxFocusIn (DtSpinBoxWidget spin, XEvent *event,
118 char **params, Cardinal *num_params);
119 static void _SpinBoxFocusOut (DtSpinBoxWidget spin, XEvent *event,
120 char **params, Cardinal *num_params);
121 static void DrawHighlight (DtSpinBoxWidget spin, Boolean clear);
122 static void _SpinBoxUp (DtSpinBoxWidget spin,
123 XEvent *event, char **params,
124 Cardinal *num_params);
125 static void _SpinBoxDown (DtSpinBoxWidget spin,
126 XEvent *event, char **params,
127 Cardinal *num_params);
128 static void _SpinBoxLeft (DtSpinBoxWidget spin,
129 XEvent *event, char **params,
130 Cardinal *num_params);
131 static void _SpinBoxRight (DtSpinBoxWidget spin,
132 XEvent *event, char **params,
133 Cardinal *num_params);
134 static void _SpinBoxBeginLine (DtSpinBoxWidget spin,
135 XEvent *event, char **params,
136 Cardinal *num_params);
137 static void _SpinBoxEndLine (DtSpinBoxWidget spin,
138 XEvent *event, char **params,
139 Cardinal *num_params);
140 static void _SpinBoxGetFocus (DtSpinBoxWidget spin,
141 XEvent *event, char **params,
142 Cardinal *num_params);
143 static void _SpinBoxPrevTabGroup (DtSpinBoxWidget spin,
144 XEvent *event, char **params,
145 Cardinal *num_params);
146 static void _SpinBoxNextTabGroup (DtSpinBoxWidget spin,
147 XEvent *event, char **params,
148 Cardinal *num_params);
150 static void CheckResources (DtSpinBoxWidget spin);
151 static void Destroy (DtSpinBoxWidget spin);
152 static void Resize (DtSpinBoxWidget spin);
153 static void Redisplay (DtSpinBoxWidget w, XEvent *event,
155 static XtGeometryResult GeometryManager (Widget w,
156 XtWidgetGeometry *request,
157 XtWidgetGeometry *reply);
158 static void SetSpinBoxSize (DtSpinBoxWidget spin);
159 static void ForceChildSizes (DtSpinBoxWidget spin);
160 static void CalculateSizes (DtSpinBoxWidget spin,
163 Dimension *parrow_width);
164 static void LayoutChildren (DtSpinBoxWidget spin);
165 static Boolean SetValues (DtSpinBoxWidget current,
166 DtSpinBoxWidget request,
167 DtSpinBoxWidget new);
168 static void ClearShadow (DtSpinBoxWidget w, Boolean all);
169 static void DrawShadow (DtSpinBoxWidget w);
170 static void StoreResourceInfo (DtSpinBoxPart *spin_p,
171 DtSpinBoxPart *old_p,
173 static char* GetTextString (XmString xm_string);
174 static void SetTextFieldData (DtSpinBoxWidget spin);
175 static void SetMaximumLabelSize (DtSpinBoxPart *spin_p);
176 static void SetLabelData (DtSpinBoxWidget spin);
177 static void timer_dispatch (XtPointer client_data, XtIntervalId *id);
178 static void TextFieldActivate (DtSpinBoxPart *spin_p);
179 static Boolean SendCallback (DtSpinBoxWidget spin, XEvent *event,
180 Boolean value_changed, int position,
181 float current, Boolean crossed);
182 static void FinishUpDown (DtSpinBoxWidget spin,
183 XtPointer arrow_call_data, int new_position,
184 float new_current, Boolean crossed);
185 static void up_cb (Widget w, XtPointer client_data,
186 XtPointer call_data);
187 static void down_cb (Widget w, XtPointer client_data,
188 XtPointer call_data);
189 static void disarm_cb (Widget w, XtPointer client_data,
190 XtPointer call_data);
191 static void grab_leave_cb (Widget w, XtPointer client_data,
192 XEvent *event, Boolean *dispatch);
193 static void text_losing_focus_cb (Widget w, XtPointer client_data,
194 XtPointer call_data);
195 static void text_activate_cb (Widget w, XtPointer client_data,
196 XtPointer call_data);
197 static void text_focus_cb (Widget w, XtPointer client_data,
198 XtPointer call_data);
199 static XmImportOperator _XmSetSyntheticResForChild (Widget widget,
203 static XmString InitLabel = NULL;
208 #define Label(w) XmField(w,ipot,DtSpinBox,label,Widget)
209 #define UpArrow(w) XmField(w,ipot,DtSpinBox,up_arrow,Widget)
210 #define DownArrow(w) XmField(w,ipot,DtSpinBox,down_arrow,Widget)
211 #define WhichArrow(w) XmField(w,ipot,DtSpinBox,which_arrow,unsigned char)
212 #define InitCb(w) XmField(w,ipot,DtSpinBox,init_cb,Boolean)
213 #define Grabbed(w) XmField(w,ipot,DtSpinBox,grabbed,Boolean)
214 #define Base(w) XmField(w,ipot,DtSpinBox,base,int)
215 #define Min(w) XmField(w,ipot,DtSpinBox,min,float)
216 #define Max(w) XmField(w,ipot,DtSpinBox,max,float)
217 #define Increment(w) XmField(w,ipot,DtSpinBox,increment,float)
218 #define Current(w) XmField(w,ipot,DtSpinBox,current,float)
219 #define FloatFormat(w) (String) &(XmField(w,ipot,DtSpinBox,float_format,char *))
220 #define OldWidth(w) XmField(w,ipot,DtSpinBox,old_width,Dimension)
221 #define OldHeight(w) XmField(w,ipot,DtSpinBox,old_height,Dimension)
222 #define LabelMaxLength(w) XmField(w,ipot,DtSpinBox,label_max_length,Dimension)
223 #define LabelMaxHeight(w) XmField(w,ipot,DtSpinBox,label_max_height,Dimension)
225 #define ArrowSensitivity(w) XmField(w,ipot,DtSpinBox,arrow_sensitivity,unsigned char)
226 #define DecimalPoints(w) XmField(w,ipot,DtSpinBox,decimal_points,short)
227 #define NumericIncrement(w) XmField(w,ipot,DtSpinBox,numeric_increment,int)
228 #define Maximum(w) XmField(w,ipot,DtSpinBox,maximum,int)
229 #define Minimum(w) XmField(w,ipot,DtSpinBox,minimum,int)
230 #define ItemCount(w) XmField(w,ipot,DtSpinBox,item_count,int)
231 #define Position(w) XmField(w,ipot,DtSpinBox,position,int)
232 #define ChildType(w) XmField(w,ipot,DtSpinBox,child_type,unsigned char)
233 #define Items(w) XmField(w,ipot,DtSpinBox,items,XmStringTable)
234 #define ActivateCallback(w) XmField(w,ipot,DtSpinBox,activate_callback,XtCallbackList)
235 #define Alignment(w) XmField(w,ipot,DtSpinBox,alignment,unsigned char)
236 #define ArrowLayout(w) XmField(w,ipot,DtSpinBox,arrow_layout,unsigned char)
237 #define ArrowSize(w) XmField(w,ipot,DtSpinBox,arrow_size,Dimension)
238 #define TextColumns(w) XmField(w,ipot,DtSpinBox,text_columns,short)
239 #define Editable(w) XmField(w,ipot,DtSpinBox,editable,Boolean)
240 #define FocusCallback(w) XmField(w,ipot,DtSpinBox,focus_callback,XtCallbackList)
241 #define InitialDelay(w) XmField(w,ipot,DtSpinBox,initial_delay,unsigned int)
242 #define LosingFocusCallback(w) XmField(w,ipot,DtSpinBox,losing_focus_callback,XtCallbackList)
243 #define MarginHeight(w) XmField(w,ipot,DtSpinBox,margin_height,Dimension)
244 #define MarginWidth(w) XmField(w,ipot,DtSpinBox,margin_width,Dimension)
245 #define TextMaxLength(w) XmField(w,ipot,DtSpinBox,text_max_length,int)
246 #define ModifyVerifyCallback(w) XmField(w,ipot,DtSpinBox,modify_verify_callback,XtCallbackList)
247 #define RecomputeSize(w) XmField(w,ipot,DtSpinBox,recompute_size,Boolean)
248 #define RepeatDelay(w) XmField(w,ipot,DtSpinBox,repeat_delay,unsigned int)
249 #define Text(w) XmField(w,ipot,DtSpinBox,text,Widget)
250 #define ValueChangedCallback(w) XmField(w,ipot,DtSpinBox,value_changed_callback,XtCallbackList)
251 #define Wrap(w) XmField(w,ipot,DtSpinBox,wrap,Boolean)
252 #define Timer(w) XmField(w,ipot,DtSpinBox,timer,XtIntervalId)
254 /* SpinBox and Superclass resource macros*/
255 #define PUnitType(w) w->primitive.unit_type
256 #define MUnitType(w) w->manager.unit_type
257 #define MFgPixel(w) w->manager.foreground
258 #define SPIN_SHADOW(w) w->manager.shadow_thickness
259 #define CBgPixel(w) w->core.background_pixel
260 #define CBgPixmap(w) w->core.background_pixmap
261 #define Width(w) w->core.width
262 #define Height(w) w->core.height
263 #define SPIN_MARGIN_W(w) MarginWidth(w)
264 #define SPIN_MARGIN_H(w) MarginHeight(w)
265 #define MAXINT 2147483647 /* Taken from TextF.c */
266 #define DEFAULT_COL 20
268 /* USL: Label get Focus */
269 static XtTranslations child_trans_label;
270 /* USL: Keyboard only for Text */
271 static XtTranslations child_trans_text;
272 static XtTranslations child_trans_arrow;
274 static XtTranslations child_trans;
275 static XtTranslations spin_trans;
278 static char const SpinBoxTranslationTable[] = "\
279 <FocusIn>: SpinBoxFocusIn() \n\
280 <FocusOut>: SpinBoxFocusOut() \n\
281 <Key>osfUp: SpinBoxUp() \n\
282 <Key>osfDown: SpinBoxDown() \n\
283 <Key>osfRight: SpinBoxRight() \n\
284 <Key>osfLeft: SpinBoxLeft() \n\
285 <Key>osfBeginLine: SpinBoxBeginLine() \n\
286 <Key>osfEndLine: SpinBoxEndLine() \n\
289 static char const SpinBoxChildTranslationTable[] = "\
290 <Key>osfUp: SpinBoxUp(child) \n\
291 <Key>osfDown: SpinBoxDown(child) \n\
292 <Key>osfRight: SpinBoxRight(child) \n\
293 <Key>osfLeft: SpinBoxLeft(child) \n\
294 <Key>osfBeginLine: SpinBoxBeginLine(child) \n\
295 <Key>osfEndLine: SpinBoxEndLine(child) \n\
298 /* #5: Label get focus */
299 static char const SpinBoxLabelTranslationTable[] = "\
300 <Key>osfUp: SpinBoxUp(child) \n\
301 <Key>osfDown: SpinBoxDown(child) \n\
302 <Key>osfRight: SpinBoxRight(child) \n\
303 <Key>osfLeft: SpinBoxLeft(child) \n\
304 <Key>osfBeginLine: SpinBoxBeginLine(child) \n\
305 <Key>osfEndLine: SpinBoxEndLine(child) \n\
306 <Key>osfDown: SpinBoxGetFocus() \n\
307 <Btn1Down>,<Btn1Up>: SpinBoxGetFocus() \n\
308 <Key>osfSelect: SpinBoxGetFocus() \n\
309 ~s ~m ~a <Key>space: SpinBoxGetFocus() \n\
312 /* USL: Keyboard Only Traversing During Editable-Mode */
313 static char const SpinBoxTextTranslationTable[] = "\
314 <Key>osfUp: SpinBoxUp(child) SpinBoxRight(child)\n\
315 <Key>osfDown: SpinBoxDown(child) SpinBoxLeft(child)\n\
317 static char const SpinBoxArrowTranslationTable[] = "\
318 <Key>osfUp: SpinBoxUp(child) \n\
319 <Key>osfDown: SpinBoxDown(child) \n\
320 <Key>osfRight: SpinBoxRight(child) \n\
321 <Key>osfLeft: SpinBoxLeft(child) \n\
322 <Key>osfBeginLine: SpinBoxBeginLine(child) \n\
323 <Key>osfEndLine: SpinBoxEndLine(child) \n\
324 s ~m ~a <Key>Tab: SpinBoxPrevTabGroup()\n\
325 ~m ~a <Key>Tab: SpinBoxNextTabGroup()\n\
329 static XtActionsRec SpinBoxActionTable[] = {
330 {"SpinBoxFocusIn", (XtActionProc)_SpinBoxFocusIn},
331 {"SpinBoxFocusOut", (XtActionProc)_SpinBoxFocusOut},
332 {"SpinBoxUp", (XtActionProc)_SpinBoxUp},
333 {"SpinBoxDown", (XtActionProc)_SpinBoxDown},
334 {"SpinBoxRight", (XtActionProc)_SpinBoxRight},
335 {"SpinBoxLeft", (XtActionProc)_SpinBoxLeft},
336 {"SpinBoxBeginLine", (XtActionProc)_SpinBoxBeginLine},
337 {"SpinBoxEndLine", (XtActionProc)_SpinBoxEndLine},
338 {"SpinBoxGetFocus", (XtActionProc)_SpinBoxGetFocus},
339 {"SpinBoxPrevTabGroup", (XtActionProc)_SpinBoxPrevTabGroup},
340 {"SpinBoxNextTabGroup", (XtActionProc)_SpinBoxNextTabGroup},
343 /* DtSpinBoxWidget resources */
345 #define offset(field) XtOffset(DtSpinBoxWidget, field)
346 #define DtOffset(field) XmPartOffset(DtSpinBox,field)
347 static XmPartResource resources[] = {
348 {XmNshadowThickness, XmCShadowThickness, XmRHorizontalDimension,
349 sizeof(Dimension), offset(manager.shadow_thickness),
350 XmRImmediate, (XtPointer)TEXT_FIELD_SHADOW},
352 /* Common resources */
353 {DtNactivateCallback, DtCCallback, XmRCallback, sizeof(XtCallbackList),
354 DtOffset(activate_callback), XmRCallback,
356 {DtNalignment, DtCAlignment, XmRAlignment, sizeof(unsigned char),
357 DtOffset(alignment), XmRImmediate,
358 (XtPointer)DtALIGNMENT_BEGINNING},
359 {DtNarrowLayout, DtCArrowLayout, DtRArrowLayout, sizeof(unsigned char),
360 DtOffset(arrow_layout), XmRImmediate,
361 (XtPointer)DtARROWS_END},
362 {DtNarrowSensitivity, DtCArrowSensitivity, DtRArrowSensitivity,
363 sizeof(unsigned char), DtOffset(arrow_sensitivity),
364 XmRImmediate, (XtPointer)DtARROWS_SENSITIVE},
365 {DtNspinBoxChildType, DtCSpinBoxChildType, DtRSpinBoxChildType,
366 sizeof(unsigned char),
367 DtOffset(child_type), XmRImmediate, (XtPointer)DtSTRING},
368 {DtNcolumns, DtCColumns, XmRShort, sizeof(short),
369 DtOffset(text_columns), XmRImmediate, (XtPointer)DEFAULT_COL},
370 {DtNdecimalPoints, DtCDecimalPoints, XmRShort, sizeof( short ),
371 DtOffset(decimal_points), XmRImmediate, (XtPointer)0},
372 {DtNeditable, DtCEditable, XmRBoolean, sizeof(Boolean),
373 DtOffset(editable), XmRImmediate, (XtPointer)TRUE},
374 {DtNfocusCallback, DtCCallback, XmRCallback, sizeof(XtCallbackList),
375 DtOffset(focus_callback), XmRCallback,
377 {DtNincrementValue, DtCIncrementValue, XmRInt, sizeof(int),
378 DtOffset(numeric_increment), XmRImmediate, (XtPointer)1},
379 {DtNinitialDelay, DtCInitialDelay, XmRInt, sizeof(unsigned int),
380 DtOffset(initial_delay), XmRImmediate, (XtPointer)250},
381 {DtNnumValues, DtCNumValues, DtRNumValues, sizeof(int),
382 DtOffset(item_count), XmRImmediate, (XtPointer)0},
383 {DtNvalues, DtCItems, XmRXmStringTable, sizeof(XmStringTable),
384 DtOffset(items), XmRImmediate, (XtPointer)NULL},
385 {DtNlosingFocusCallback, DtCCallback, XmRCallback, sizeof(XtCallbackList),
386 DtOffset(losing_focus_callback), XmRCallback,
388 {DtNmarginHeight, DtCMarginHeight, XmRVerticalDimension, sizeof(Dimension),
389 DtOffset(margin_height), XmRImmediate, (XtPointer)MARGIN},
390 {DtNmarginWidth, DtCMarginWidth, XmRHorizontalDimension, sizeof(Dimension),
391 DtOffset(margin_width), XmRImmediate, (XtPointer)MARGIN},
392 {DtNmaximumValue, DtCMaximumValue, XmRInt, sizeof(int),
393 DtOffset(maximum), XmRImmediate, (XtPointer)10},
394 {DtNmaxLength, DtCMaxLength, XmRInt, sizeof(int),
395 DtOffset(text_max_length), XmRImmediate, (XtPointer)MAXINT},
396 {DtNminimumValue, DtCMinimumValue, XmRInt, sizeof(int),
397 DtOffset(minimum), XmRImmediate, (XtPointer)0},
398 {DtNmodifyVerifyCallback, DtCCallback, XmRCallback,
399 sizeof(XtCallbackList), DtOffset(modify_verify_callback),
400 XmRCallback, (XtPointer)NULL},
401 {DtNposition, DtCPosition, XmRInt, sizeof(int),
402 DtOffset(position), XmRImmediate, (XtPointer)0},
403 {DtNrecomputeSize, DtCRecomputeSize, XmRBoolean, sizeof(Boolean),
404 DtOffset(recompute_size), XmRImmediate, (XtPointer)TRUE},
405 {DtNrepeatDelay, DtCRepeatDelay, XmRInt, sizeof(unsigned int),
406 DtOffset(repeat_delay), XmRImmediate, (XtPointer)200},
407 {DtNtextField, DtCTextField, XmRWidget, sizeof(Widget),
408 DtOffset(text), XmRImmediate, (XtPointer)NULL},
409 {DtNvalueChangedCallback, DtCCallback, XmRCallback,
410 sizeof(XtCallbackList), DtOffset(value_changed_callback),
411 XmRCallback, (XtPointer)NULL},
412 {DtNwrap, DtCWrap, XmRBoolean, sizeof(Boolean),
413 DtOffset(wrap), XmRImmediate, (XtPointer)TRUE},
416 /* Synthetic resources. Only used for Motif API arrowSize right now */
417 static XmSyntheticResource syn_resources[] = {
418 {DtNarrowSize, sizeof(Dimension), DtOffset(arrow_size),
419 _DtSpinBoxGetArrowSize, _XmSetSyntheticResForChild},
420 {DtNmarginHeight, sizeof(Dimension), DtOffset(margin_height),
421 XmeFromVerticalPixels, XmeToVerticalPixels},
422 {DtNmarginWidth, sizeof(Dimension), DtOffset(margin_width),
423 XmeFromHorizontalPixels, XmeToHorizontalPixels},
428 /* Need Class Extension for widget navigation */
429 static XmBaseClassExtRec baseClassExtRec = {
432 XmBaseClassExtVersion,
433 sizeof(XmBaseClassExtRec),
434 (XtInitProc)NULL, /* InitializePrehook */
435 (XtSetValuesFunc)NULL, /* SetValuesPrehook */
436 (XtInitProc)NULL, /* InitializePosthook */
437 (XtSetValuesFunc)NULL, /* SetValuesPosthook */
438 NULL, /* secondaryObjectClass */
439 (XtInitProc)NULL, /* secondaryCreate */
440 (XmGetSecResDataFunc)NULL, /* getSecRes data */
441 { 0 }, /* fastSubclass flags */
442 (XtArgsProc)NULL, /* getValuesPrehook */
443 (XtArgsProc)NULL, /* getValuesPosthook */
444 (XtWidgetClassProc)NULL, /* classPartInitPrehook */
445 (XtWidgetClassProc)NULL, /* classPartInitPosthook*/
446 NULL, /* ext_resources */
447 NULL, /* compiled_ext_resources*/
448 0, /* num_ext_resources */
449 FALSE, /* use_sub_resources */
450 (XmWidgetNavigableProc)WidgetNavigable,
451 /* widgetNavigable */
452 (XmFocusChangeProc)NULL, /* focusChange */
453 (XmWrapperData)NULL /* wrapperData */
457 * Define Class Record.
459 externaldef(dtspinboxclassrec) DtSpinBoxClassRec dtSpinBoxClassRec =
461 { /* core_class fields */
462 (WidgetClass)&(xmManagerClassRec), /* superclass */
463 (String)"DtSpinBox", /* class_name */
464 (Cardinal)sizeof(DtSpinBoxPart), /* widget_size */
465 (XtProc)ClassInitialize, /* class_initialize */
466 (XtWidgetClassProc)NULL, /* class_part_init */
467 (XtEnum)FALSE, /* class_inited */
468 (XtInitProc)Initialize, /* initialize */
469 (XtArgsProc)NULL, /* initialize_hook */
470 (XtRealizeProc)XtInheritRealize, /* realize */
471 (XtActionList)SpinBoxActionTable, /* actions */
472 (Cardinal)XtNumber(SpinBoxActionTable), /* num_actions */
473 (XtResourceList)resources, /* resources */
474 (Cardinal)XtNumber(resources), /* num_resources */
475 (XrmClass)NULLQUARK, /* xrm_class */
476 (Boolean)TRUE, /* compress_motion */
477 (XtEnum)XtExposeCompressMaximal, /* compress_exposure */
478 (Boolean)TRUE, /* compress_enterleave*/
479 (Boolean)FALSE, /* visible_interest */
480 (XtWidgetProc)Destroy, /* destroy */
481 (XtWidgetProc)Resize, /* resize */
482 (XtExposeProc)Redisplay, /* expose */
483 (XtSetValuesFunc)SetValues, /* set_values */
484 (XtArgsFunc)NULL, /* set values hook */
485 (XtAlmostProc)XtInheritSetValuesAlmost, /* set values almost */
486 (XtArgsProc)NULL, /* get values hook */
487 (XtAcceptFocusProc)NULL, /* accept_focus */
488 (XtVersionType)XtVersionDontCheck, /* Version */
489 (XtPointer)NULL, /* PRIVATE cb list */
490 (String)XtInheritTranslations, /* tm_table */
491 (XtGeometryHandler)XtInheritQueryGeometry, /* query_geom */
492 (XtStringProc)XtInheritDisplayAccelerator, /* display_accelerator*/
493 (XtPointer)&baseClassExtRec /* extension */
495 { /* composite_class fields */
496 (XtGeometryHandler)GeometryManager, /* geometry_manager */
497 (XtWidgetProc)XtInheritChangeManaged, /* change_managed */
498 (XtWidgetProc)XtInheritInsertChild, /* insert_child */
499 (XtWidgetProc)XtInheritDeleteChild, /* delete_child */
500 (XtPointer)NULL /* extension */
502 { /* constraint_class fields */
503 (XtResourceList)NULL, /* resources */
504 (Cardinal)0, /* num_resources */
505 (Cardinal)0, /* constraint_size */
506 (XtInitProc)NULL, /* initialize */
507 (XtWidgetProc)NULL, /* destroy */
508 (XtSetValuesFunc)NULL, /* set_values */
509 (XtPointer)NULL /* extension */
511 { /* manager class */
512 (String)XtInheritTranslations, /* translations */
513 (XmSyntheticResource*)syn_resources, /* syn resources */
514 (int)XtNumber(syn_resources), /* num syn_resources */
515 (XmSyntheticResource*)NULL, /* get_cont_resources */
516 (int)0, /* num_get_cont_resources */
517 (XmParentProcessProc)XmInheritParentProcess,/* parent_process */
518 (XtPointer)NULL /* extension */
520 { /* spin_box_class fields */
525 externaldef(dtspinboxwidgetclass) WidgetClass dtSpinBoxWidgetClass =
526 (WidgetClass)&dtSpinBoxClassRec;
528 static XmRepTypeId _DtRID_SB_ARROW_SENSITIVITY_TYPE;
529 static String _DtArrowSensitivityNames[] = {
530 "arrows_insensitive",
531 "arrows_increment_sensitive",
532 "arrows_decrement_sensitive",
537 * Must set up the record type for the class extensions to work.
540 ClassInitialize(void)
542 baseClassExtRec.record_type = XmQmotif;
546 XmResolveAllPartOffsets(dtSpinBoxWidgetClass, &ipot, &cpot);
548 child_trans = XtParseTranslationTable(SpinBoxChildTranslationTable);
549 spin_trans = XtParseTranslationTable(SpinBoxTranslationTable);
551 child_trans_label=XtParseTranslationTable(SpinBoxLabelTranslationTable);
552 child_trans_text=XtParseTranslationTable(SpinBoxTextTranslationTable);
553 child_trans_arrow=XtParseTranslationTable(SpinBoxArrowTranslationTable);
555 _DtRID_SB_ARROW_SENSITIVITY_TYPE =
556 XmRepTypeRegister(DtRArrowSensitivity, _DtArrowSensitivityNames,
557 NULL, XtNumber(_DtArrowSensitivityNames));
559 InitLabel = XmStringCreateLocalized(SB_LABEL);
563 * SpinBox initialization function. This builds the widgets inside
564 * our widget, to get the correct layout. If the editable resource
565 * is TRUE, we create a textField; if FALSE, we create a label. If the
566 * user changes this resource later, we will create the other widget
567 * (textField or Label). We don't want to carry backage from both
568 * widgets if the user never changes the editable resource.
571 Initialize( DtSpinBoxWidget request,
576 DtSpinBoxPart *spin_p = (DtSpinBoxPart*)
577 &(XmField(new,ipot,DtSpinBox,label,Widget));
581 /* Resolution Independent */
582 unsigned char unit_type = MUnitType(new);
584 /* Overwrite the manager's focusIn and focusOut translations */
585 XtOverrideTranslations((Widget)new, spin_trans);
587 widget_name = XtMalloc(strlen(XtName((Widget)new)) + 10);
589 Text(new) = (Widget)NULL;
590 Label(new) = (Widget)NULL;
594 Grabbed(new) = FALSE;
599 * Create the text or label depending on editable resource.
602 sprintf(widget_name, "%s_TF", XtName((Widget)new));
604 XtSetArg(args[n], XmNmaxLength, TextMaxLength(new)); n++;
605 XtSetArg(args[n], XmNmarginWidth, TEXT_CONTEXT_MARGIN); n++;
606 XtSetArg(args[n], XmNmarginHeight, 2); n++;
607 /* Resolution Independent */
608 if (unit_type != XmPIXELS) {
609 XtSetArg(args[n], XmNunitType, XmPIXELS); n++;
611 Text(new) = XtCreateManagedWidget(widget_name,
612 xmTextFieldWidgetClass,
613 (Widget)new, args, n);
614 XtAddCallback(Text(new), XmNlosingFocusCallback,
615 text_losing_focus_cb, (XtPointer)new);
616 XtAddCallback(Text(new), XmNactivateCallback,
617 text_activate_cb, (XtPointer)new);
618 XtAddCallback(Text(new), XmNfocusCallback,
619 text_focus_cb, (XtPointer)new);
621 XtOverrideTranslations((Widget)Text(new), child_trans_text);
623 if (TextColumns(request) == DEFAULT_COL && Width(request)) {
625 CalculateSizes(new, &width, NULL, NULL);
626 XtSetArg(args[n], XmNwidth, width); n++;
629 XtSetArg(args[n], XmNcolumns, TextColumns(new)); n++;
631 if (unit_type != XmPIXELS) {
632 XtSetArg(args[n], XmNunitType, unit_type); n++;
634 XtSetValues(Text(new), args, n);
637 sprintf(widget_name, "%s_Label", XtName((Widget)new));
638 SPIN_SHADOW(new) = LABEL_SHADOW;
640 XtSetArg(args[n], XmNalignment, Alignment(new)); n++;
641 XtSetArg(args[n], XmNrecomputeSize, FALSE); n++;
642 XtSetArg(args[n], XmNlabelString, InitLabel); n++;
643 XtSetArg(args[n], XmNmarginLeft, LABEL_PADDING); n++;
644 XtSetArg(args[n], XmNmarginRight, LABEL_PADDING); n++;
645 XtSetArg(args[n], XmNmarginWidth, TEXT_CONTEXT_MARGIN); n++;
646 XtSetArg(args[n], XmNmarginHeight, 2); n++;
647 if (unit_type != XmPIXELS) {
648 XtSetArg(args[n], XmNunitType, XmPIXELS); n++;
650 Label(new) = XtCreateManagedWidget(widget_name, xmLabelWidgetClass,
651 (Widget)new, args, n);
653 XtOverrideTranslations((Widget)Label(new), child_trans_label);
655 if (unit_type != XmPIXELS) {
656 XtSetArg(args[n], XmNunitType, unit_type); n++;
660 CalculateSizes(new, &width, NULL, NULL);
661 XtSetArg(args[n], XmNwidth, width); n++;
664 XtSetValues(Label(new), args, n);
668 * Create the 2 ArrowWidgets.
670 sprintf(widget_name, "%s_Up", XtName((Widget)new));
672 if (ArrowLayout(new) == DtARROWS_SPLIT) {
673 XtSetArg(args[n], XmNarrowDirection, XmARROW_RIGHT); n++;
675 XtSetArg(args[n], XmNhighlightThickness, 0); n++;
676 XtSetArg(args[n], XmNshadowThickness, 0); n++;
677 XtSetArg(args[n], XmNtraversalOn, FALSE); n++;
678 XtSetArg(args[n], XmNforeground, CBgPixel(new)); n++;
679 UpArrow(new) = XtCreateManagedWidget(widget_name,
680 xmArrowButtonWidgetClass,
681 (Widget)new, args, n);
682 XtOverrideTranslations((Widget)UpArrow(new), child_trans_arrow);
684 sprintf(widget_name, "%s_Down", XtName((Widget)new));
685 if (ArrowLayout(new) == DtARROWS_SPLIT) {
686 XtSetArg(args[n], XmNarrowDirection, XmARROW_LEFT); n++;
689 XtSetArg(args[n], XmNarrowDirection, XmARROW_DOWN); n++;
691 DownArrow(new) = XtCreateManagedWidget(widget_name,
692 xmArrowButtonWidgetClass,
693 (Widget)new, args, n);
694 XtOverrideTranslations((Widget)DownArrow(new), child_trans_arrow);
696 /* Set sensitivity of arrows (up arrow is right arrow) */
697 if ((ArrowSensitivity(new) == DtARROWS_INSENSITIVE) ||
698 (ArrowSensitivity(new) == DtARROWS_DECREMENT_SENSITIVE))
699 XtSetSensitive(UpArrow(new), FALSE);
700 if ((ArrowSensitivity(new) == DtARROWS_INSENSITIVE) ||
701 (ArrowSensitivity(new) == DtARROWS_INCREMENT_SENSITIVE))
702 XtSetSensitive(DownArrow(new), FALSE);
705 * Arm causes the value to change and the timer to start.
706 * Disarm (leaveNotify from grab) causes the timer to stop.
708 XtAddCallback(UpArrow(new), XmNarmCallback, up_cb, (XtPointer)new);
709 XtAddCallback(UpArrow(new), XmNdisarmCallback, disarm_cb,
711 XtAddEventHandler(UpArrow(new), LeaveWindowMask, FALSE, grab_leave_cb,
713 XtAddCallback(DownArrow(new), XmNarmCallback, down_cb, (XtPointer)new);
714 XtAddCallback(DownArrow(new), XmNdisarmCallback, disarm_cb,
716 XtAddEventHandler(DownArrow(new), LeaveWindowMask, FALSE,
717 grab_leave_cb, (XtPointer)new);
719 /* Initialize everything based on what the resource values are */
720 StoreResourceInfo(spin_p, NULL, TRUE);
723 * Set initial value in text or label if items was specified
725 if (Editable(new) == FALSE) {
727 SetMaximumLabelSize(spin_p);
731 SetTextFieldData(new);
737 /* Store Converter for DtNmaximumValue, DtNminimumValue, DtNincrementValue,
739 XtSetTypeConverter(XmRString, DtRMaximumValue, XtCvtStringToInt, NULL, 0,
741 XtSetTypeConverter(XmRString, DtRMinimumValue, XtCvtStringToInt, NULL, 0,
743 XtSetTypeConverter(XmRString, DtRIncrementValue, XtCvtStringToInt, NULL, 0,
745 XtSetTypeConverter(XmRString, DtRNumValues, XtCvtStringToInt, NULL, 0,
748 * this is so these resources can be set uniformly through XtCreateWidget
749 * or through defaults file as *spin.backgound
753 XtSetArg(args[n],XmNbackground,CBgPixel(new));n++;
754 XtSetArg(args[n],XmNbackgroundPixmap,CBgPixmap(new));n++;
755 XtSetArg(args[n],XmNforeground,MFgPixel(new));n++;
757 XtSetValues (Text(new),args,n);
759 XtSetValues (Label(new),args,n);
761 XtSetValues (UpArrow(new),args,n);
763 XtSetValues (DownArrow(new),args,n);
769 * Allow the manager to gain focus if not editable. If editable (using
770 * text-field), then let the toolkit give focus to the text-field.
772 static XmNavigability
773 WidgetNavigable(DtSpinBoxWidget spin)
775 XmNavigationType nav_type = ((XmManagerWidget)spin)->manager.navigation_type;
777 if (spin->core.sensitive && spin->core.ancestor_sensitive &&
778 ((XmManagerWidget)spin)->manager.traversal_on) {
779 if ((nav_type == XmSTICKY_TAB_GROUP) ||
780 (nav_type == XmEXCLUSIVE_TAB_GROUP) ||
781 ((nav_type == XmTAB_GROUP) &&
782 !_XmShellIsExclusive((Widget)spin))) {
784 return(XmDESCENDANTS_TAB_NAVIGABLE);
786 return(XmTAB_NAVIGABLE);
788 return(XmDESCENDANTS_NAVIGABLE);
790 return(XmNOT_NAVIGABLE);
794 * The spin_box gets focus.
797 _SpinBoxFocusIn( DtSpinBoxWidget spin,
800 Cardinal *num_params)
802 DrawHighlight(spin, FALSE);
806 * The spin_box loses focus.
809 _SpinBoxFocusOut( DtSpinBoxWidget spin,
812 Cardinal *num_params)
814 DrawHighlight(spin, TRUE);
818 * This function gets called whenever we draw or clear the shadow (to
819 * redraw highlight during resize, etc), as well as during focus_in
820 * and focus_out events.
823 DrawHighlight( DtSpinBoxWidget spin,
828 if (XtIsRealized((Widget)spin)) {
830 rect[0].x = rect[1].x = rect[2].x = 0;
831 rect[3].x = OldWidth(spin) - SPIN_MARGIN_W(spin);
832 rect[0].y = rect[2].y = rect[3].y = 0 ;
833 rect[1].y = OldHeight(spin) - SPIN_MARGIN_H(spin);
834 rect[0].width = rect[1].width = OldWidth(spin);
835 rect[2].width = rect[3].width = SPIN_MARGIN_W(spin);
836 rect[0].height = rect[1].height = SPIN_MARGIN_H(spin);
837 rect[2].height = rect[3].height = OldHeight(spin);
838 XFillRectangles(XtDisplayOfObject((Widget)spin),
839 XtWindowOfObject((Widget)spin),
840 spin->manager.background_GC, rect, 4);
842 else if (XmGetFocusWidget((Widget)spin) == (Widget)spin) {
843 rect[0].x = rect[1].x = rect[2].x = 0;
844 rect[3].x = XtWidth(spin) - SPIN_MARGIN_W(spin);
845 rect[0].y = rect[2].y = rect[3].y = 0 ;
846 rect[1].y = XtHeight(spin) - SPIN_MARGIN_H(spin);
847 rect[0].width = rect[1].width = XtWidth(spin);
848 rect[2].width = rect[3].width = SPIN_MARGIN_W(spin);
849 rect[0].height = rect[1].height = SPIN_MARGIN_H(spin);
850 rect[2].height = rect[3].height = XtHeight(spin);
851 XFillRectangles(XtDisplayOfObject((Widget)spin),
852 XtWindowOfObject((Widget)spin),
853 spin->manager.highlight_GC, rect, 4);
860 * osfUp virtual key hit. Simulate hitting the up arrow.
863 _SpinBoxUp( DtSpinBoxWidget spin,
866 Cardinal *num_params)
868 if (*num_params != 0) /* params means label or arrows */
869 spin = (DtSpinBoxWidget)XtParent(spin);
871 if (ArrowLayout(spin) != DtARROWS_SPLIT) {
872 up_cb((Widget)UpArrow(spin), (XtPointer)spin, NULL);
873 disarm_cb((Widget)UpArrow(spin), (XtPointer)spin, NULL);
878 * osfDown virtual key hit. Simulate hitting the down arrow.
881 _SpinBoxDown(DtSpinBoxWidget spin,
884 Cardinal *num_params)
886 if (*num_params != 0) /* params means label or arrows */
887 spin = (DtSpinBoxWidget)XtParent(spin);
889 if (ArrowLayout(spin) != DtARROWS_SPLIT) {
890 down_cb((Widget)DownArrow(spin), (XtPointer)spin, NULL);
891 disarm_cb((Widget)DownArrow(spin), (XtPointer)spin, NULL);
896 * osfRight virtual key hit. Simulate hitting the up arrow.
899 _SpinBoxRight(DtSpinBoxWidget spin,
902 Cardinal *num_params)
904 if (*num_params != 0) /* params means label or arrows */
905 spin = (DtSpinBoxWidget)XtParent(spin);
907 if (ArrowLayout(spin) == DtARROWS_SPLIT) {
908 up_cb((Widget)UpArrow(spin), (XtPointer)spin, NULL);
909 disarm_cb((Widget)UpArrow(spin), (XtPointer)spin, NULL);
914 * osfLeft virtual key hit. Simulate hitting the down arrow.
917 _SpinBoxLeft(DtSpinBoxWidget spin,
920 Cardinal *num_params)
922 if (*num_params != 0) /* params means label or arrows */
923 spin = (DtSpinBoxWidget)XtParent(spin);
925 if (ArrowLayout(spin) == DtARROWS_SPLIT) {
926 down_cb((Widget)DownArrow(spin), (XtPointer)spin, NULL);
927 disarm_cb((Widget)DownArrow(spin), (XtPointer)spin, NULL);
932 * osfBeginLine virtual key hit. Go to first item.
935 _SpinBoxBeginLine( DtSpinBoxWidget spin,
938 Cardinal *num_params)
943 if (*num_params != 0) /* params means label or arrows */
944 spin = (DtSpinBoxWidget)XtParent(spin);
946 if (ChildType(spin) == DtNUMERIC) {
947 new_position = Minimum(spin);
948 new_current = Min(spin);
953 if (SendCallback(spin, event, FALSE, new_position,
954 new_current, FALSE) == TRUE) {
955 /* User said yes, so set widget values */
956 Position(spin) = new_position;
957 Current(spin) = new_current;
959 SetTextFieldData(spin);
963 /* send value_changed callback */
964 (void)SendCallback(spin, event, TRUE, Position(spin),
965 Current(spin), FALSE);
970 * osfEndLine virtual key hit. Go to last item.
973 _SpinBoxEndLine( DtSpinBoxWidget spin,
976 Cardinal *num_params)
981 if (*num_params != 0) /* params means label or arrows */
982 spin = (DtSpinBoxWidget)XtParent(spin);
984 if (ChildType(spin) == DtNUMERIC) {
985 new_position = Maximum(spin);
986 new_current = Max(spin);
989 new_position = ItemCount(spin) - 1;
991 if (SendCallback(spin, event, FALSE, new_position,
992 new_current, FALSE) == TRUE) {
993 /* User said yes, so set widget values */
994 Position(spin) = new_position;
995 Current(spin) = new_current;
997 SetTextFieldData(spin);
1001 /* send value_changed callback */
1002 (void)SendCallback(spin, event, TRUE, Position(spin),
1003 Current(spin), FALSE);
1008 * USL: Get Focus for SpinBox when hit its label part
1011 _SpinBoxGetFocus( DtSpinBoxWidget spin,
1014 Cardinal *num_params)
1016 XmProcessTraversal((Widget)XtParent(spin),
1017 (XmTraversalDirection) XmTRAVERSE_CURRENT);
1021 * USL: Process Focus Traversal for SpinBox when cursor is in its arrow part
1024 _SpinBoxPrevTabGroup(DtSpinBoxWidget spin,
1027 Cardinal *num_params)
1029 XmProcessTraversal((Widget)XtParent(spin),
1030 (XmTraversalDirection) XmTRAVERSE_PREV_TAB_GROUP);
1034 _SpinBoxNextTabGroup(DtSpinBoxWidget spin,
1037 Cardinal *num_params)
1039 XmProcessTraversal((Widget)XtParent(spin),
1040 (XmTraversalDirection) XmTRAVERSE_NEXT_TAB_GROUP);
1044 * This function goes through most of the resources and makes sure
1045 * they have legal values.
1048 CheckResources(DtSpinBoxWidget spin)
1050 if (!XmRepTypeValidValue(_DtRID_SB_ARROW_SENSITIVITY_TYPE,
1051 ArrowSensitivity(spin), (Widget)spin)) {
1052 XtWarning(SB_ARROW_SENSITIVE);
1053 ArrowSensitivity(spin) = DtARROWS_SENSITIVE;
1055 if ((Alignment(spin) != DtALIGNMENT_CENTER) &&
1056 (Alignment(spin) != DtALIGNMENT_BEGINNING) &&
1057 (Alignment(spin) != DtALIGNMENT_END)) {
1058 XtWarning(SB_ALIGNMENT);
1059 Alignment(spin) = DtALIGNMENT_CENTER;
1061 if (InitialDelay(spin) == 0) {
1062 XtWarning(SB_INIT_DELAY);
1063 InitialDelay(spin) = 250;
1065 if ((ArrowLayout(spin) != DtARROWS_FLAT_BEGINNING) &&
1066 (ArrowLayout(spin) != DtARROWS_FLAT_END) &&
1067 (ArrowLayout(spin) != DtARROWS_SPLIT) &&
1068 (ArrowLayout(spin) != DtARROWS_BEGINNING) &&
1069 (ArrowLayout(spin) != DtARROWS_END)) {
1070 XtWarning(SB_ARROW_LAYOUT);
1071 ArrowLayout(spin) = DtARROWS_BEGINNING;
1073 if (RepeatDelay(spin) == 0) {
1074 XtWarning(SB_REPEAT_DELAY);
1075 RepeatDelay(spin) = 200;
1077 if (ItemCount(spin) < 0) {
1078 XtWarning(SB_ITEM_COUNT);
1079 ItemCount(spin) = 0;
1081 if ((ChildType(spin) == DtSTRING) &&
1082 ((Position(spin) < 0) ||
1083 ((Position(spin) >= ItemCount(spin)) &&
1084 (ItemCount(spin) > 0)))) {
1085 XtWarning(SB_POSITION_STRING);
1088 if ((DecimalPoints(spin) < 0) ||
1089 (DecimalPoints(spin) > MAX_FLOAT_DECIMALS)) {
1090 XtWarning(SB_DECIMAL_POINTS);
1091 DecimalPoints(spin) = 0;
1093 if (Minimum(spin) > Maximum(spin)) {
1094 XtWarning(SB_MIN_MAX);
1095 Minimum(spin) = Maximum(spin);
1097 if ((ChildType(spin) == DtNUMERIC) &&
1098 ((Position(spin) < Minimum(spin)) ||
1099 (Position(spin) > Maximum(spin)) ||
1100 ((Position(spin) % NumericIncrement(spin)) != 0))) {
1101 XtWarning(SB_POSITION_NUMERIC);
1102 Position(spin) = Minimum(spin);
1108 * Destroy procedure called by the toolkit.
1111 Destroy(DtSpinBoxWidget spin)
1115 if ((int)Timer(spin))
1117 XtRemoveTimeOut(Timer(spin));
1118 Timer(spin) = (XtIntervalId)NULL;
1121 if (ItemCount(spin)>0) {
1122 for (i = 0; i < ItemCount(spin); i++) {
1123 XmStringFree((Items(spin))[i]);
1125 XtFree((char*)(Items(spin)));
1129 * Don't remove callbacks and event handlers set on the children,
1130 * this has already been done by Xt (children are cleaned up before
1137 * Resize function called by toolkit. The size of our spin-box
1138 * has already been changed. That is why we must store
1139 * old_width and old_height.
1142 Resize(DtSpinBoxWidget spin)
1144 ClearShadow(spin, TRUE);
1145 LayoutChildren(spin);
1147 OldWidth(spin) = spin->core.width;
1148 OldHeight(spin) = spin->core.height;
1153 * Redisplay function called by toolkit. The widget didn't change size,
1154 * so just redisplay the shadow.
1157 Redisplay( DtSpinBoxWidget w,
1166 * GeometryManager function called by toolkit when a child resizes/moves.
1167 * We are not allowing any changes but width/height of the text-field.
1168 * this is because the user can retrieve the text-field and make changes
1169 * that we want to honor. If they mess around with the label or arrow,
1170 * then we won't honor the request.
1171 * If the text-field requests a change, then make the change, and allow
1172 * our SetSpinBoxSize() and LayoutChildren() figure out what size will
1174 * Returning GeometryDone was suppose to tell the toolkit
1175 * that we resized the child ourselves, but the text-field had trouble
1176 * with this (its' geometry_manager wasn't called or working right?), so
1177 * we return GeometryYes.
1179 static XtGeometryResult
1180 GeometryManager(Widget w, /* child */
1181 XtWidgetGeometry *request,
1182 XtWidgetGeometry *reply)
1185 DtSpinBoxWidget spin = (DtSpinBoxWidget)XtParent(w);
1186 /* Resolution Independent */
1188 Dimension width, height, border_width;
1190 unsigned char unit_type;
1192 /* Ignore everything but text-field */
1193 if (w != Text(spin) ) {
1194 return(XtGeometryNo);
1197 /* Only allow width/height changes */
1198 if (!(request->request_mode & (CWWidth | CWHeight)))
1199 return(XtGeometryNo);
1201 /* Resolution Independent */
1202 XtSetArg(args[0], XmNunitType, &unit_type);
1203 XtGetValues(w, args, 1);
1204 if ( unit_type != XmPIXELS) {
1205 XtSetArg(args[0], XmNunitType, XmPIXELS);
1206 XtSetValues(w, args, 1);
1209 /* Set the text-field to the requested size */
1210 if (request->request_mode & CWWidth) {
1212 XtSetArg(args[n], XmNwidth, &width); n++;
1214 if (request->request_mode & CWHeight) {
1216 XtSetArg(args[n], XmNheight, &height); n++;
1219 XtSetArg(args[n], XmNborderWidth, &border_width); n++;
1220 XtGetValues(w, args, n);
1221 XtResizeWidget(w, width, height, border_width);
1222 if ( unit_type != XmPIXELS) {
1223 XtSetArg(args[0], XmNunitType, unit_type);
1224 XtSetValues(w, args, 1);
1227 ClearShadow(spin, TRUE);
1228 if (RecomputeSize(spin))
1229 SetSpinBoxSize(spin);
1230 LayoutChildren(spin);
1232 return(XtGeometryDone);
1236 * This function sets the size of the spin_box widget based on the
1237 * current size of the children. Don't worry if it doesn't work, the
1238 * children will be squeezed in later.
1241 SetSpinBoxSize(DtSpinBoxWidget spin)
1243 Widget text_holder = Editable(spin) ? Text(spin) : Label(spin);
1244 Dimension shadow = SPIN_SHADOW(spin) * 2;
1245 Dimension arrow_width, arrow_height;
1246 /* MotifBc & Resolution Independent */
1247 Dimension height, width;
1249 unsigned char unit_type = MUnitType(spin);
1252 /* Resolution Independent */
1253 if (unit_type != XmPIXELS) {
1254 XtSetArg(args[0], XmNunitType, XmPIXELS);
1255 XtSetValues((Widget)spin, args, 1);
1256 XtSetValues(text_holder, args, 1);
1259 XtSetArg(args[0], XmNheight, &height);
1260 XtSetArg(args[1], XmNwidth, &width);
1261 XtGetValues(text_holder, args, 2);
1263 * Find out how big the arrow can be (needed to get
1264 * width for text_holder).
1266 arrow_width = (Dimension)((float)height * ARROW_MULT);
1267 arrow_width = (arrow_width < ARROW_MIN) ? ARROW_MIN : arrow_width;
1269 /* Get height based on arrow width */
1270 arrow_height = arrow_width;
1271 if ((ArrowLayout(spin) == DtARROWS_BEGINNING) ||
1272 (ArrowLayout(spin) == DtARROWS_END))
1273 arrow_height += arrow_height;
1275 /* Make height bigger of 2 - arrows vs text_holder */
1276 if (arrow_height > (Dimension)height)
1277 height = arrow_height;
1279 /* If not stacked add extra width for arrows */
1280 if ((ArrowLayout(spin) != DtARROWS_BEGINNING) &&
1281 (ArrowLayout(spin) != DtARROWS_END)) {
1282 arrow_width += arrow_width;
1285 (void)XtMakeResizeRequest((Widget)spin, arrow_width +
1287 (SPIN_MARGIN_W(spin) * 2),
1288 height + shadow + (SPIN_MARGIN_H(spin) * 2),
1290 OldWidth(spin) = Width(spin);
1291 OldHeight(spin) = Height(spin);
1293 /* Resolution Independent */
1294 if (unit_type != XmPIXELS) {
1295 XtSetArg(args[0], XmNunitType, unit_type);
1296 XtSetValues((Widget)spin, args, 1);
1297 XtSetValues(text_holder, args, 1);
1302 * This function makes the text_holder (label or text-field) smaller
1303 * if the spin_box couldn't grow to the needed full size. It will
1304 * also make the text_holder grow if there is space. The textfield will
1305 * grow with the spin_box, but the label will only grow to its'
1306 * maximum size. The label will also shrink down to nothing, but the
1307 * text-field will always keep its' core height.
1310 ForceChildSizes(DtSpinBoxWidget spin)
1312 Dimension available_height, available_width, arrow_width;
1313 /* MotifBc & Resolution Independent */
1315 unsigned char unit_type = XmPIXELS;
1317 /* Resolution Independent */
1318 if (MUnitType(spin) != XmPIXELS) {
1319 unit_type = MUnitType(spin);
1320 XtSetArg(args[0], XmNunitType, XmPIXELS);
1321 XtSetValues(UpArrow(spin), args, 1);
1322 XtSetValues(DownArrow(spin), args, 1);
1323 if (Editable(spin) == False)
1324 XtSetValues(Label(spin), args, 1);
1326 XtSetValues(Text(spin), args, 1);
1329 CalculateSizes(spin, &available_width, &available_height, &arrow_width);
1331 if (Editable(spin) == FALSE) { /** label **/
1332 if (available_width > LabelMaxLength(spin))
1333 available_width = LabelMaxLength(spin);
1335 if ((available_width != (Label(spin))->core.width) ||
1336 (available_height != (Label(spin))->core.height))
1337 XtResizeWidget(Label(spin), available_width, available_height,
1338 (Label(spin))->core.border_width);
1340 else if ((Text(spin))->core.width != available_width) /** TextField **/
1341 XtResizeWidget(Text(spin), available_width,
1342 (Text(spin))->core.height,
1343 (Text(spin))->core.border_width);
1344 if ((arrow_width != UpArrow(spin)->core.width) ||
1345 ((UpArrow(spin))->core.height != arrow_width)) {
1346 available_height = (available_height < ARROW_MIN) ? ARROW_MIN :
1348 XtResizeWidget(UpArrow(spin), arrow_width, arrow_width,
1349 (UpArrow(spin))->core.border_width);
1351 if ((arrow_width != (DownArrow(spin))->core.width) ||
1352 ((DownArrow(spin))->core.height != arrow_width)) {
1353 available_height = (available_height < ARROW_MIN) ? ARROW_MIN :
1355 XtResizeWidget(DownArrow(spin), arrow_width, arrow_width,
1356 DownArrow(spin)->core.border_width);
1358 /* Resolution Independent */
1359 if (MUnitType(spin) != XmPIXELS) {
1360 XtSetArg(args[0], XmNunitType, unit_type);
1361 XtSetValues(UpArrow(spin), args, 1);
1362 XtSetValues(DownArrow(spin), args, 1);
1363 if (Editable(spin) == False)
1364 XtSetValues(Label(spin), args, 1);
1366 XtSetValues(Text(spin), args, 1);
1371 CalculateSizes (DtSpinBoxWidget spin,
1374 Dimension *parrow_width)
1376 Dimension width, height, arrow_width;
1378 /* Calculate available height for children */
1379 if ((height = spin->core.height - (SPIN_SHADOW(spin) * 2) -
1380 (SPIN_MARGIN_H(spin) * 2)) <= 0)
1383 /* Get initial available width for children */
1384 width = (spin->core.width - (SPIN_SHADOW(spin) * 2) -
1385 (SPIN_MARGIN_W(spin) * 2));
1387 /* label only grows to maximum width needed */
1388 if ((Editable(spin) == FALSE) &&
1389 (height > LabelMaxHeight(spin)))
1390 height = LabelMaxHeight(spin);
1391 else if (Editable(spin))
1392 height = (Text(spin))->core.height;
1395 * Find out how big the arrow can be (needed to get
1396 * width for text_holder).
1398 arrow_width = (Dimension)(height * ARROW_MULT);
1399 arrow_width = (arrow_width < ARROW_MIN) ? ARROW_MIN : arrow_width;
1401 /* Make sure width isn't too small or too big */
1402 if ((width -= arrow_width) <= 0)
1405 /* If not stacked subtract extra arrow */
1406 if ((ArrowLayout(spin) != DtARROWS_BEGINNING) &&
1407 (ArrowLayout(spin) != DtARROWS_END)) {
1408 width -= arrow_width;
1411 if (pwidth) *pwidth = width;
1412 if (pheight) *pheight = height;
1413 if (parrow_width) *parrow_width = arrow_width;
1417 * This function positions the children within the spin_box widget.
1418 * It calls ForceChildSizes() to make sure the children fit within the
1419 * spin_box widget, but it will not try to resize the spin_box widget.
1422 LayoutChildren(DtSpinBoxWidget spin)
1424 Widget text_holder = Editable(spin) ? Text(spin) : Label(spin);
1425 Position start_x = SPIN_SHADOW(spin) + SPIN_MARGIN_W(spin);
1426 Position start_y = SPIN_SHADOW(spin) + SPIN_MARGIN_H(spin);
1427 Dimension available_height = spin->core.height - (start_y * 2);
1428 Position y, arrow_y;
1429 Dimension arrow_height;
1430 /* Resolution Independent */
1432 unsigned char unit_type = XmPIXELS;
1434 ForceChildSizes(spin);
1436 /* Resolution Independent */
1437 if (MUnitType(spin) != XmPIXELS) {
1438 unit_type = MUnitType(spin);
1439 XtSetArg(args[0], XmNunitType, XmPIXELS);
1440 XtSetValues(UpArrow(spin), args, 1);
1441 XtSetValues(DownArrow(spin), args, 1);
1442 XtSetValues(text_holder, args, 1);
1445 /* Center text_holder within spin_box */
1446 y = available_height - text_holder->core.height;
1447 y = ((y < 0) ? 0 : y)/2 + start_y;
1449 arrow_height = (UpArrow(spin))->core.height;
1450 if ((ArrowLayout(spin) == DtARROWS_BEGINNING) ||
1451 (ArrowLayout(spin) == DtARROWS_END))
1452 arrow_height += arrow_height;
1453 arrow_y = available_height - arrow_height;
1454 arrow_y = ((arrow_y < 0) ? 0 : arrow_y)/2 + start_y;
1456 switch (ArrowLayout(spin)) {
1457 case DtARROWS_FLAT_BEGINNING:
1458 XtMoveWidget(UpArrow(spin), start_x, arrow_y);
1459 start_x += (UpArrow(spin))->core.width;
1460 XtMoveWidget(DownArrow(spin), start_x, arrow_y);
1461 start_x += (DownArrow(spin))->core.width;
1462 XtMoveWidget(text_holder, start_x, y);
1464 case DtARROWS_FLAT_END:
1465 XtMoveWidget(text_holder, start_x, y);
1467 * This start_x places arrow right after text_holder. With
1468 * labels we want the arrow at the end of the spin_box, so
1469 * the user can use recompute_size more effectively.
1470 * start_x += text_holder->core.width;
1472 start_x = (spin->core.width - start_x -
1473 (UpArrow(spin))->core.width -
1474 (DownArrow(spin))->core.width);
1475 XtMoveWidget(UpArrow(spin), start_x, arrow_y);
1476 start_x += (UpArrow(spin))->core.width;
1477 XtMoveWidget(DownArrow(spin), start_x, arrow_y);
1479 case DtARROWS_SPLIT:
1480 XtMoveWidget(DownArrow(spin), start_x, arrow_y);
1481 start_x += (DownArrow(spin))->core.width;
1482 XtMoveWidget(text_holder, start_x, y);
1483 start_x += text_holder->core.width;
1484 XtMoveWidget(UpArrow(spin), start_x, arrow_y);
1486 case DtARROWS_BEGINNING:
1487 XtMoveWidget(UpArrow(spin), start_x, arrow_y);
1488 arrow_y += (UpArrow(spin))->core.height;
1489 XtMoveWidget(DownArrow(spin), start_x, arrow_y);
1490 start_x += (DownArrow(spin))->core.width;
1491 XtMoveWidget(text_holder, start_x, y);
1494 XtMoveWidget(text_holder, start_x, y);
1496 * This start_x places arrow right after text_holder. With
1497 * labels we want the arrow at the end of the spin_box, so
1498 * the user can use recompute_size more effectively.
1499 * start_x += text_holder->core.width;
1501 start_x = spin->core.width - start_x - (UpArrow(spin))->core.width;
1502 XtMoveWidget(UpArrow(spin), start_x, arrow_y);
1503 arrow_y += (UpArrow(spin))->core.width;
1504 XtMoveWidget(DownArrow(spin), start_x, arrow_y);
1507 /* Resolution Independent */
1508 if (MUnitType(spin) != XmPIXELS) {
1509 XtSetArg(args[0], XmNunitType, unit_type);
1510 XtSetValues(UpArrow(spin), args, 1);
1511 XtSetValues(DownArrow(spin), args, 1);
1512 XtSetValues(text_holder, args, 1);
1518 * SetValues() routine for SpinBox widget. Most of the real work
1519 * is done in SetItems() and SetNumeric(). If items is set we store
1520 * our own XmStrings.
1521 * This function was built with static spin_boxs in mind, meaning that
1522 * is-numeric or editable resources won't be changed constantly. These
1523 * resources can be changed, but this function doesn't handle them in
1524 * a super-efficient manor. for example, changing child-type will cause
1525 * the label to be resize even if it isn't managed.
1528 SetValues( DtSpinBoxWidget current,
1529 DtSpinBoxWidget request,
1530 DtSpinBoxWidget new)
1532 DtSpinBoxPart *new_p = (DtSpinBoxPart*)
1533 &(XmField(new,ipot,DtSpinBox,label,Widget));
1534 DtSpinBoxPart *cur_p = (DtSpinBoxPart*)
1535 &(XmField(current,ipot,DtSpinBox,label,Widget));
1538 Boolean label_size_changed = FALSE;
1541 /* Resolution Independent */
1542 unsigned char unit_type = MUnitType(new);
1544 CheckResources(new);
1546 if (Text(new) != Text(current)) {
1548 Text(new) = Text(current);
1552 * Editable resource changed. If the widget (textField or Label)
1553 * doesn't exist, then create it.
1555 if (Editable(new) != Editable(current)) {
1556 if (Editable(new)) {
1557 XtUnmanageChild(Label(new));
1558 if (Text(new) == NULL) {
1559 widget_name = XtMalloc(strlen(XtName((Widget)new)) + 10);
1560 sprintf(widget_name, "%s_TF", XtName((Widget)new));
1562 XtSetArg(args[n], XmNcolumns, TextColumns(new)); n++;
1563 XtSetArg(args[n], XmNmaxLength, TextMaxLength(new)); n++;
1564 XtSetArg(args[n], XmNmarginWidth, 2); n++;
1565 XtSetArg(args[n], XmNmarginHeight, 2); n++;
1566 if (unit_type != XmPIXELS) {
1567 XtSetArg(args[n], XmNunitType, XmPIXELS); n++;
1569 Text(new) = XtCreateManagedWidget(widget_name,
1570 xmTextFieldWidgetClass,
1571 (Widget)new, args, n);
1572 XtAddCallback(Text(new), XmNlosingFocusCallback,
1573 text_losing_focus_cb, (XtPointer)new);
1574 XtAddCallback(Text(new), XmNactivateCallback,
1575 text_activate_cb, (XtPointer)new);
1576 XtAddCallback(Text(new), XmNfocusCallback,
1577 text_focus_cb, (XtPointer)new);
1578 XtFree(widget_name);
1579 if (unit_type != XmPIXELS) {
1580 XtSetArg(args[n], XmNunitType, unit_type); n++;
1581 XtSetValues(Text(new), args, 1);
1585 XtManageChild(Text(new));
1588 XtUnmanageChild(Text(new));
1589 if (Label(new) == NULL) {
1590 widget_name = XtMalloc(strlen(XtName((Widget)new)) + 10);
1591 sprintf(widget_name, "%s_Label", XtName((Widget)new));
1593 XtSetArg(args[n], XmNalignment, Alignment(new)); n++;
1594 XtSetArg(args[n], XmNrecomputeSize, FALSE); n++;
1595 XtSetArg(args[n], XmNlabelString, InitLabel); n++;
1596 XtSetArg(args[n], XmNmarginLeft, LABEL_PADDING); n++;
1597 XtSetArg(args[n], XmNmarginRight, LABEL_PADDING); n++;
1598 XtSetArg(args[n], XmNmarginWidth, TEXT_CONTEXT_MARGIN); n++;
1599 XtSetArg(args[n], XmNmarginHeight, 0); n++;
1600 if (unit_type != XmPIXELS) {
1601 XtSetArg(args[n], XmNunitType, XmPIXELS); n++;
1603 Label(new) = XtCreateManagedWidget(widget_name,
1605 (Widget)new, args, n);
1606 XtOverrideTranslations((Widget)Label(new), child_trans);
1607 XtFree(widget_name);
1608 if (unit_type != XmPIXELS) {
1609 XtSetArg(args[n], XmNunitType, unit_type); n++;
1610 XtSetValues(Label(new), args, 1);
1614 XtManageChild(Label(new));
1617 * Text-fields and labels have different shadows. Only
1618 * change if user didn't change the shadow resource.
1620 if (SPIN_SHADOW(new) == SPIN_SHADOW(current))
1621 SPIN_SHADOW(new) = (Editable(new)) ? TEXT_FIELD_SHADOW :
1625 /* Check arrow sensitivity (up arrow is right arrow)*/
1626 if (ArrowSensitivity(new) != ArrowSensitivity(current)) {
1627 XtSetSensitive(UpArrow(new),
1628 ((ArrowSensitivity(new) == DtARROWS_SENSITIVE) ||
1629 (ArrowSensitivity(new) == DtARROWS_INCREMENT_SENSITIVE)));
1630 XtSetSensitive(DownArrow(new),
1631 ((ArrowSensitivity(new) == DtARROWS_SENSITIVE) ||
1632 (ArrowSensitivity(new) == DtARROWS_DECREMENT_SENSITIVE)));
1636 * Check arrow layout. Only need to change arrows if going to or
1637 * from DtARROWS_SPLIT. The LayoutChildren() routine actually
1638 * positions the arrows in the correct place.
1640 if (ArrowLayout(new) != ArrowLayout(current)) {
1641 if (ArrowLayout(new) == DtARROWS_SPLIT) {
1642 XtSetArg(args[0], XmNarrowDirection, XmARROW_RIGHT);
1643 XtSetValues(UpArrow(new), args, 1);
1644 XtSetArg(args[0], XmNarrowDirection, XmARROW_LEFT);
1645 XtSetValues(DownArrow(new), args, 1);
1648 XtSetArg(args[0], XmNarrowDirection, XmARROW_UP);
1649 XtSetValues(UpArrow(new), args, 1);
1650 XtSetArg(args[0], XmNarrowDirection, XmARROW_DOWN);
1651 XtSetValues(DownArrow(new), args, 1);
1655 if (Text(new) && (Text(new) == Text(current))) {
1657 if (TextColumns(new) != TextColumns(current)) {
1658 XtSetArg(args[n], XmNcolumns, TextColumns(new)); n++;
1660 if (TextMaxLength(new) != TextMaxLength(current)) {
1661 XtSetArg(args[n], XmNmaxLength, TextMaxLength(new)); n++;
1664 XtSetValues(Text(new), args, n);
1668 * LabelWidget alignment has changed.
1670 if (Label(new) && (Alignment(new) != Alignment(current))) {
1671 XtSetArg(args[0], XmNalignment, Alignment(new));
1672 XtSetValues(Label(new), args, 1);
1675 store_info = ((Items(new) != Items(current)) ||
1676 (ItemCount(new) != ItemCount(current)) ||
1677 (DecimalPoints(new) != DecimalPoints(current)) ||
1678 (Maximum(new) != Maximum(current)) ||
1679 (Minimum(new) != Minimum(current)) ||
1680 (NumericIncrement(new) != NumericIncrement(current)) ||
1681 ((ChildType(new) == DtNUMERIC) &&
1682 (Position(new) != Position(current))));
1684 StoreResourceInfo(new_p, cur_p, (Items(new) != Items(current)));
1686 if (Label(new) && (store_info ||
1687 (Label(new) != Label(current)) ||
1688 (ChildType(new) != ChildType(current)))) {
1689 SetMaximumLabelSize(new_p);
1690 label_size_changed = TRUE;
1694 (Alignment(new) != Alignment(current)) ||
1695 (Editable(new) != Editable(current)) ||
1696 (Position(new) != Position(current)) ||
1697 (Label(new) != Label(current)) ||
1698 (ChildType(new) != ChildType(current))) {
1700 SetTextFieldData(new);
1706 * Must recalculate the spin_box and re-layout the children.
1707 * If this is not editable, then set the label to its' maximum
1708 * size; it will get chopped if it is too big. This is needed
1709 * because we shrink the label down, and SetSpinBoxSize() uses
1710 * the label's core sizes to figure what size to become.
1712 if ((Editable(new) != Editable(current)) ||
1713 (SPIN_MARGIN_W(new) != SPIN_MARGIN_W(current)) ||
1714 (SPIN_MARGIN_H(new) != SPIN_MARGIN_H(current)) ||
1715 (SPIN_SHADOW(new) != SPIN_SHADOW(current)) ||
1716 (ArrowLayout(new) != ArrowLayout(current)) ||
1717 (!(Editable(new)) && label_size_changed)) {
1718 ClearShadow(current, TRUE);
1719 if (RecomputeSize(new))
1720 SetSpinBoxSize(new);
1721 LayoutChildren(new);
1725 if(CBgPixel(new) != CBgPixel(current))
1727 XtSetArg(args[n],XmNbackground,CBgPixel(new));n++;
1729 if(CBgPixmap(new) != CBgPixmap(current))
1731 XtSetArg(args[n],XmNbackgroundPixmap,CBgPixmap(new));n++;
1733 if(MFgPixel(new) != MFgPixel(current))
1735 XtSetArg(args[n],XmNforeground,MFgPixel(new));n++;
1738 XtSetValues (Text(new),args,n);
1740 XtSetValues (Label(new),args,n);
1742 XtSetValues (UpArrow(new),args,n);
1744 XtSetValues (DownArrow(new),args,n);
1751 * This function clears the shadow around our widget. If all is TRUE,
1752 * then clear all 4 sides; otherwise, only clear the right and bottom
1753 * sides (during resize).
1756 ClearShadow( DtSpinBoxWidget w,
1759 Dimension shadow = SPIN_SHADOW(w);
1760 Dimension margin_w = SPIN_MARGIN_W(w);
1761 Dimension margin_h = SPIN_MARGIN_H(w);
1763 if ((shadow > 0) && XtIsRealized((Widget)w)) {
1765 XClearArea(XtDisplayOfObject((Widget)w),
1766 XtWindowOfObject((Widget)w),
1768 OldWidth(w) - (margin_w * 2),
1770 XClearArea(XtDisplayOfObject((Widget)w),
1771 XtWindowOfObject((Widget)w),
1772 margin_w, margin_h, shadow,
1773 OldHeight(w) - (margin_h * 2), FALSE);
1775 XClearArea(XtDisplayOfObject((Widget)w), XtWindowOfObject((Widget)w),
1776 margin_w, OldHeight(w) - margin_h - shadow,
1777 OldWidth(w) - (margin_w * 2), shadow, FALSE);
1778 XClearArea(XtDisplayOfObject((Widget)w), XtWindowOfObject((Widget)w),
1779 OldWidth(w) - margin_w - shadow,
1781 OldHeight(w) - (margin_h * 2), FALSE);
1783 DrawHighlight(w, TRUE);
1787 * This functions draws the shadow around our spin_box.
1790 DrawShadow(DtSpinBoxWidget w)
1792 Dimension shadow = SPIN_SHADOW(w);
1793 Dimension margin_w = SPIN_MARGIN_W(w);
1794 Dimension margin_h = SPIN_MARGIN_H(w);
1796 if ((shadow > 0) && XtIsRealized((Widget)w)) {
1797 XmeDrawShadows(XtDisplayOfObject((Widget)w),
1798 XtWindowOfObject((Widget)w),
1799 w->manager.top_shadow_GC,
1800 w->manager.bottom_shadow_GC,
1802 w->core.width - (margin_w * 2),
1803 w->core.height - (margin_h * 2),
1804 shadow, XmSHADOW_OUT);
1806 DrawHighlight(w, FALSE);
1810 * This function sets up the items information for the SpinBox, as
1811 * well as variables needed for child_type.
1814 StoreResourceInfo( DtSpinBoxPart *spin_p,
1815 DtSpinBoxPart *old_p,
1818 XmStringTable table;
1821 if (do_items && spin_p->items) {
1822 /* Free up current items if needed */
1823 if (old_p && old_p->items) {
1824 for (i = 0; i < old_p->item_count; i++) {
1825 XmStringFree(old_p->items[i]);
1827 XtFree((char*)old_p->items);
1831 * Loop through all the items, copy them into our space.
1833 table = (XmStringTable)XtMalloc(sizeof(XmString) * spin_p->item_count);
1834 for (i = 0; i < spin_p->item_count; i++) {
1835 table[i] = XmStringCopy(spin_p->items[i]);
1837 spin_p->items = table;
1838 for (i = 0; i < spin_p->item_count; i++)
1839 spin_p->items[i] = table[i];
1843 * Store the numeric information
1846 /* get base number for convert ints to floats */
1847 for (i = 0; i < spin_p->decimal_points; i++)
1850 /* Set new initial values */
1851 spin_p->min = (float)spin_p->minimum/base;
1852 spin_p->max = (float)spin_p->maximum/base;
1853 spin_p->increment = (float)spin_p->numeric_increment/base;
1855 spin_p->current = (float)spin_p->position/base;
1857 /* Create format string used to build correct XmString value */
1858 spin_p->float_format[0] = '%';
1859 sprintf((char*)(spin_p->float_format+1), ".%df", spin_p->decimal_points);
1863 /* Caller must free string */
1865 GetTextString(XmString xm_string)
1867 XmStringContext context;
1868 XmStringComponentType type;
1869 XmStringCharSet charset;
1870 XmStringDirection direction;
1871 XmStringComponentType unknown_tag;
1875 Boolean done = FALSE;
1877 XmStringInitContext(&context, xm_string);
1879 /* Loop until 1st char* found */
1881 type = XmStringGetNextComponent(context, &text, &charset,
1882 &direction, &unknown_tag,
1885 case XmSTRING_COMPONENT_END:
1888 case XmSTRING_COMPONENT_TEXT:
1889 case XmSTRING_COMPONENT_LOCALE_TEXT:
1896 XmStringFreeContext(context);
1901 * Take the string out of the list and put it into the text-field.
1902 * text-fields don't handle xm-strings, so we must get the char*
1903 * out of it (only getting the first segment). This is slower than
1904 * storing the text-strings (char*) ourselves, but that would take
1905 * up a lot of memory. Since this setting happens during a user
1906 * action, speed isn't a problem.
1909 SetTextFieldData(DtSpinBoxWidget spin)
1911 char string[NUMERIC_LENGTH];
1917 if (ChildType(spin) == DtNUMERIC) {
1918 sprintf(string, FloatFormat(spin), (float)(Current(spin)));
1919 XtSetArg(arg, XmNvalue, string);
1920 XtSetValues(Text(spin), &arg, 1);
1923 if (ItemCount(spin) == 0){
1924 XtSetArg(arg, XmNvalue, "");
1925 XtSetValues(Text(spin), &arg, 1);
1929 xm_string = (Items(spin))[Position(spin)];
1930 if ((text = GetTextString(xm_string))) {
1931 XtSetArg(arg, XmNvalue, text);
1932 XtSetValues(Text(spin), &arg, 1);
1940 * Set the maximum size of the label, depending on the
1941 * characteristics of the list of items. Not very efficient
1942 * if switching from numeric to non-numeric.
1945 SetMaximumLabelSize(DtSpinBoxPart *spin_p)
1948 XmFontList font_list;
1949 char string[NUMERIC_LENGTH];
1950 Dimension width, height;
1951 Dimension longest = 0;
1952 Dimension highest = 0;
1955 /* Resolution Independent */
1956 unsigned char unit_type;
1958 /* Get font info from the widget */
1959 XtSetArg(args[0], XmNfontList, &font_list);
1960 XtSetArg(args[1], XmNunitType, &unit_type); /* resolution Independent */
1961 XtGetValues(spin_p->label, args, 2);
1962 if ( unit_type != XmPIXELS) {
1963 XtSetArg(args[0], XmNunitType, XmPIXELS);
1964 XtSetValues(spin_p->label, args, 1);
1967 if (spin_p->child_type == DtNUMERIC) {
1968 /* Find out maximum size of the widget from min/max */
1969 sprintf(string, spin_p->float_format, spin_p->min);
1970 xm_string = XmStringCreateLocalized(string);
1971 XmStringExtent(font_list, xm_string, &longest, &highest);
1972 XmStringFree(xm_string);
1973 sprintf(string, spin_p->float_format, spin_p->max);
1974 xm_string = XmStringCreateLocalized(string);
1975 XmStringExtent(font_list, xm_string, &width, &height);
1976 XmStringFree(xm_string);
1978 longest = (width > longest) ? width : longest;
1979 highest = (height > highest) ? height : highest;
1981 else if (spin_p->items) {
1983 * Loop through all the items to find the biggest dimensions
1985 for (i = 0; i < spin_p->item_count; i++) {
1986 XmStringExtent(font_list, spin_p->items[i], &width, &height);
1987 longest = (width > longest) ? width : longest;
1988 highest = (height > highest) ? height : highest;
1992 XmStringExtent(font_list, InitLabel, &longest, &highest);
1995 spin_p->label_max_length =
1996 ( (Dimension)(longest + ( (LABEL_PADDING + TEXT_CONTEXT_MARGIN) *2) ) >
1997 (Dimension)Width(spin_p->label) ) ?
1998 (longest + ((LABEL_PADDING+TEXT_CONTEXT_MARGIN) * 2)) :
1999 Width(spin_p->label);
2001 spin_p->label_max_height = highest > Height(spin_p->label) ?
2002 highest : Height(spin_p->label);
2003 XtResizeWidget(spin_p->label, spin_p->label_max_length,
2004 spin_p->label_max_height,
2005 spin_p->label->core.border_width);
2007 /* Resolution Independent */
2008 if ( unit_type != XmPIXELS) {
2009 XtSetArg(args[0], XmNunitType, unit_type);
2010 XtSetValues(spin_p->label, args, 1);
2016 * Put the current list item into the label.
2019 SetLabelData(DtSpinBoxWidget spin)
2022 char string[NUMERIC_LENGTH];
2023 int index = Position(spin);
2026 if (ChildType(spin) == DtNUMERIC) {
2027 sprintf(string, FloatFormat(spin), (float)Current(spin));
2028 xm_string = XmStringCreateLocalized(string);
2029 XtSetArg(arg, XmNlabelString, xm_string);
2030 XtSetValues(Label(spin), &arg, 1);
2034 * If the item is not empty, get the current item from the list, else
2037 xm_string = (ItemCount(spin)>0) ? (Items(spin))[index] : InitLabel;
2038 XtSetArg(arg, XmNlabelString, xm_string);
2039 XtSetValues(Label(spin), &arg, 1);
2044 * Timout dispatch routine. This calls the appropriate callback function
2045 * to simulate up or down arrow activation.
2048 timer_dispatch( XtPointer client_data,
2051 DtSpinBoxWidget spin_w = (DtSpinBoxWidget)client_data;
2053 Timer(spin_w) = (XtIntervalId)NULL;
2054 InitCb(spin_w) = FALSE;
2055 if (WhichArrow(spin_w) == XmARROW_UP) {
2056 if (Grabbed(spin_w)) {
2057 XtRemoveGrab(UpArrow(spin_w));
2058 Grabbed(spin_w) = FALSE;
2060 up_cb(NULL, client_data, NULL);
2063 if (Grabbed(spin_w)) {
2064 XtRemoveGrab(DownArrow(spin_w));
2065 Grabbed(spin_w) = FALSE;
2067 down_cb(NULL, client_data, NULL);
2072 TextFieldActivate(DtSpinBoxPart *spin_p)
2074 XmTextFieldWidget w = (XmTextFieldWidget)(spin_p->text);
2075 XmAnyCallbackStruct cb;
2076 char string[NUMERIC_LENGTH];
2080 Boolean free_me = TRUE;
2082 XtSetArg(arg, XmNvalue, &data);
2083 XtGetValues((Widget)w, &arg, 1);
2085 if (spin_p->child_type == DtNUMERIC) {
2086 sprintf(string, spin_p->float_format, (float)spin_p->current);
2090 else if (spin_p->items)
2091 text = GetTextString(spin_p->items[spin_p->position]);
2093 if (text && data && (strcmp(text, data) == 0)) {
2098 /* Only send callback if both are not NULL */
2099 else if (!((text == NULL) && (data == NULL))) {
2100 cb.reason = XmCR_ACTIVATE;
2103 if (XtHasCallbacks((Widget)w, XmNactivateCallback)==XtCallbackHasSome)
2104 XtCallCallbacks((Widget)w, XmNactivateCallback,
2106 if (text && free_me)
2112 * This function calls the appropriate callback for the spin_box.
2113 * It gathers the correct arguments and fills in the callback structure.
2116 SendCallback( DtSpinBoxWidget spin,
2118 Boolean value_changed,
2120 float current, /* Used for numeric */
2123 DtSpinBoxCallbackStruct cb;
2124 XmString xm_string = NULL;
2125 char string[NUMERIC_LENGTH];
2127 if (ChildType(spin) == DtNUMERIC) {
2128 sprintf(string, FloatFormat(spin), (float)current);
2129 xm_string = XmStringCreateLocalized(string);
2132 xm_string = (ItemCount(spin)>0) ? (Items(spin))[position] : InitLabel;
2133 xm_string = XmStringCopy(xm_string);
2137 cb.reason = DtCR_OK;
2138 else if (WhichArrow(spin) == XmARROW_UP)
2139 cb.reason = DtCR_SPIN_NEXT;
2141 cb.reason = DtCR_SPIN_PRIOR;
2144 cb.widget = (Widget)spin;
2145 cb.position = position;
2146 cb.value = xm_string;
2147 cb.crossed_boundary = crossed;
2148 if (value_changed) {
2149 XtCallCallbackList((Widget)spin, ValueChangedCallback(spin),
2154 XtCallCallbackList((Widget)spin, ModifyVerifyCallback(spin),
2157 XmStringFree(xm_string);
2164 * This function gets called by the up/down arm callback functions.
2165 * We set up the timer and send the modify-verify and value-changed
2167 * There are potential problems if the user does some weird stuff
2168 * in the callbacks. I have added protection against the case where
2169 * a user does a grab (with XtAddGrab/XtPopup/etc.) in the callbacks.
2170 * Grabbing in the callback would cause us to lose the button-release
2171 * (disarm), which would make the timer go on forever. A grab is
2172 * done after the callbacks just to make sure we will receive the
2173 * button-release. The button-release will call disarm_cb() which will
2174 * un-grab and disable the timer. I have also added a leave callback
2175 * which helps to protect against these kinds of problems.
2176 * If the callback goes into another event-loop (which I hope would
2177 * never happen), we would spin continuously (since our XtAddGrab never
2178 * get called), until the user left the window (which would call
2179 * grab_leave_cb). The grabbed flag gets set if we do the grab, so that
2180 * we know if we can remove the grab. Our XtAddGrab() might not get called
2181 * if the callback enters another event-loop.
2183 * The event sent in the callback will be NULL during continuous spinning.
2186 FinishUpDown( DtSpinBoxWidget spin,
2187 XtPointer arrow_call_data,
2192 XmArrowButtonCallbackStruct *arrow_data;
2193 XEvent *last_event = NULL;
2194 int repeat_delay = RepeatDelay(spin);
2197 repeat_delay = InitialDelay(spin);
2198 Timer(spin) = XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)spin),
2199 repeat_delay, timer_dispatch, (XtPointer)spin);
2201 /* Try to get Xevent */
2202 if ((arrow_data = (XmArrowButtonCallbackStruct*)arrow_call_data))
2203 last_event = arrow_data->event;
2206 * Send modify_verify callback. If user says no, then
2207 * clear the timer and reset the state before returning.
2209 if (SendCallback(spin, last_event, FALSE, new_position,
2210 new_current, crossed) == FALSE) {
2211 XtRemoveTimeOut(Timer(spin));
2212 Timer(spin) = (XtIntervalId)NULL;
2213 InitCb(spin) = TRUE;
2217 /* User said yes, so set widget values */
2218 Position(spin) = new_position;
2219 Current(spin) = new_current;
2221 SetTextFieldData(spin);
2225 /* send value_changed callback */
2226 (void)SendCallback(spin, last_event, TRUE, Position(spin),
2227 Current(spin), crossed);
2229 /* See notes at top of function on XtAddGrab usage */
2230 Grabbed(spin) = TRUE;
2231 if (WhichArrow(spin) == XmARROW_UP)
2232 XtAddGrab(UpArrow(spin), FALSE, FALSE);
2234 XtAddGrab(DownArrow(spin), FALSE, FALSE);
2238 * Show the next value in the SpinBox. If numeric, just add the
2239 * increment value. If using string-table, get the next one in the
2240 * table. This function takes care of wrap around. Set the arrow
2241 * type. This is needed for the timer_dispatch function. up_cb
2242 * gets called the first time the button is pressed, and each time the
2244 * All widget internals are expected to be correct here; they
2245 * get verified when set by the user.
2249 XtPointer client_data,
2250 XtPointer call_data)
2252 DtSpinBoxWidget spin = (DtSpinBoxWidget)client_data;
2253 DtSpinBoxPart *spin_p = (DtSpinBoxPart*)
2254 &(XmField(spin,ipot,DtSpinBox,label,Widget));
2255 Boolean crossed_boundary = FALSE;
2256 int new_position = Position(spin);
2257 float new_current = Current(spin);
2260 if ( !_XmFocusIsHere( (Widget)spin) )
2261 XmProcessTraversal((Widget)spin,
2262 (XmTraversalDirection) XmTRAVERSE_CURRENT);
2265 TextFieldActivate(spin_p);
2268 * If non-numeric and no items then ignore the user activate event.
2270 if ((ChildType(spin) == DtSTRING) && (ItemCount(spin) == 0))
2273 if (ChildType(spin) == DtNUMERIC) {
2274 if ((new_current + Increment(spin)) > Max(spin)) {
2276 new_position = Minimum(spin);
2277 new_current = Min(spin);
2278 crossed_boundary = TRUE;
2281 XBell(XtDisplayOfObject((Widget)spin), 0);
2284 new_position += NumericIncrement(spin);
2285 new_current += Increment(spin);
2288 else if (ItemCount(spin) >0) {
2289 if (new_position == (ItemCount(spin) - 1)) {
2292 crossed_boundary = TRUE;
2295 XBell(XtDisplayOfObject((Widget)spin), 0);
2301 WhichArrow(spin) = XmARROW_UP;
2302 FinishUpDown(spin, call_data, new_position, new_current, crossed_boundary);
2307 * Show the previous value in the SpinBox. If numeric, just decrement
2308 * the increment value. If using string-table, get the previous one in the
2309 * table. This function takes care of wrap around. Set the arrow
2310 * type. This is needed for the timer_dispatch function. down_cb
2311 * gets called the first time the button is pressed, and each time the
2313 * All widget internals are expected to be correct here; they
2314 * get verified when set by the user.
2318 XtPointer client_data,
2319 XtPointer call_data)
2321 DtSpinBoxWidget spin = (DtSpinBoxWidget)client_data;
2322 DtSpinBoxPart *spin_p = (DtSpinBoxPart*)
2323 &(XmField(spin,ipot,DtSpinBox,label,Widget));
2324 Boolean crossed_boundary = FALSE;
2325 int new_position = Position(spin);
2326 float new_current = Current(spin);
2328 /* #5: Getting Focus */
2329 if ( !_XmFocusIsHere( (Widget)spin) )
2330 XmProcessTraversal((Widget)spin,
2331 (XmTraversalDirection) XmTRAVERSE_CURRENT);
2334 TextFieldActivate(spin_p);
2337 * If non-numeric and no items then ignore the user activate event.
2339 if ((ChildType(spin) == DtSTRING) && (ItemCount(spin) == 0))
2342 if (ChildType(spin) == DtNUMERIC) {
2343 if ((new_current - Increment(spin)) < Min(spin)) {
2345 new_current = Max(spin);
2346 new_position = Maximum(spin);
2347 crossed_boundary = TRUE;
2350 XBell(XtDisplayOfObject((Widget)spin), 0);
2353 new_current -= Increment(spin);
2354 new_position -= NumericIncrement(spin);
2357 else if (ItemCount(spin)>0) {
2358 if (new_position == 0) {
2360 new_position = ItemCount(spin) - 1;
2361 crossed_boundary = TRUE;
2364 XBell(XtDisplayOfObject((Widget)spin), 0);
2370 WhichArrow(spin) = XmARROW_DOWN;
2371 FinishUpDown(spin, call_data, new_position, new_current, crossed_boundary);
2375 disarm_cb( Widget w,
2376 XtPointer client_data,
2377 XtPointer call_data)
2379 DtSpinBoxWidget spin = (DtSpinBoxWidget)client_data;
2381 if ((int)Timer(spin)) {
2382 InitCb(spin) = TRUE;
2383 XtRemoveTimeOut(Timer(spin));
2384 Timer(spin) = (XtIntervalId)NULL;
2385 if (Grabbed(spin)) {
2387 Grabbed(spin) = FALSE;
2393 grab_leave_cb( Widget w,
2394 XtPointer client_data,
2398 DtSpinBoxWidget spin = (DtSpinBoxWidget)client_data;
2400 if ((int)Timer(spin) &&
2401 ((event->xcrossing.mode == NotifyGrab) ||
2402 (event->xcrossing.mode == NotifyUngrab) ||
2403 (!(event->xcrossing.state & Button1Mask)))) {
2404 InitCb(spin) = TRUE;
2405 XtRemoveTimeOut(Timer(spin));
2406 Timer(spin) = (XtIntervalId)NULL;
2407 if (Grabbed(spin)) {
2409 Grabbed(spin) = FALSE;
2415 * We get the text-field losing-focus callback, so pass it on to
2416 * the user if they requested it. Our losing-focus callback
2417 * is just a convenience callback, so that the user doesn't
2418 * have to get the text-field first. This make our integration
2419 * with XDesigner a little easier.
2422 text_losing_focus_cb( Widget w,
2423 XtPointer client_data,
2424 XtPointer call_data)
2426 DtSpinBoxWidget spin = (DtSpinBoxWidget)client_data;
2428 if (LosingFocusCallback(spin))
2429 XtCallCallbackList((Widget)spin,
2430 LosingFocusCallback(spin),
2431 (XtPointer)call_data);
2435 * We get the text-field activate callback, so pass it on to
2436 * the user if they requested it. Our activate callback
2437 * is just a convenience callback, so that the user doesn't
2438 * have to get the text-field first. This make our integration
2439 * with XDesigner a little easier.
2442 text_activate_cb(Widget w,
2443 XtPointer client_data,
2444 XtPointer call_data)
2446 DtSpinBoxWidget spin = (DtSpinBoxWidget)client_data;
2448 if (ActivateCallback(spin))
2449 XtCallCallbackList((Widget)spin,
2450 ActivateCallback(spin),
2451 (XtPointer)call_data);
2455 * We get the text-field focus callback, so pass it on to
2456 * the user if they requested it. Our focus callback
2457 * is just a convenience callback, so that the user doesn't
2458 * have to get the text-field first. This make our integration
2459 * with XDesigner a little easier.
2462 text_focus_cb( Widget w,
2463 XtPointer client_data,
2464 XtPointer call_data)
2466 DtSpinBoxWidget spin = (DtSpinBoxWidget)client_data;
2468 if (FocusCallback(spin))
2469 XtCallCallbackList((Widget)spin,
2470 FocusCallback(spin),
2471 (XtPointer)call_data);
2476 * Synthetic resource get functions.
2479 static XmImportOperator
2480 _XmSetSyntheticResForChild( Widget widget,
2484 return(XmSYNTHETIC_LOAD);
2488 _DtSpinBoxGetArrowSize( Widget w,
2489 int resource_offset,
2492 DtSpinBoxWidget spin = (DtSpinBoxWidget)w;
2497 XtSetArg(arg, XmNheight, &data);
2498 XtGetValues(UpArrow(spin), &arg, 1);
2499 *value = (XtArgVal)data;
2503 * Routines which manipulate the SpinBox list. These are external
2504 * for use by users of our widget.
2508 DtCreateSpinBox( Widget parent,
2513 return(XtCreateWidget(name, dtSpinBoxWidgetClass, parent,
2514 arglist, num_args));
2518 DtSpinBoxAddItem( Widget spinw,
2522 DtSpinBoxWidget spin = (DtSpinBoxWidget)spinw;
2523 DtSpinBoxPart *spin_p;
2524 XmString old, new_str, tmp;
2526 _DtWidgetToAppContext(spinw);
2529 spin_p = (DtSpinBoxPart*) &(XmField(spin,ipot,DtSpinBox,label,Widget));
2531 total_items = ItemCount(spin) + 1;
2532 Items(spin) = (XmString *)XtRealloc((char*)Items(spin),
2533 (sizeof(XmString) * total_items));
2534 new_str = XmStringCopy(item);
2536 pos--; /* User gives pos starting at 1 (0 means end of list) */
2538 if ((pos < 0) || (pos > ItemCount(spin)))
2539 pos = ItemCount(spin);
2541 if (pos >= ItemCount(spin))
2542 (Items(spin))[pos] = new_str;
2544 old = (Items(spin))[pos];
2545 (Items(spin))[pos] = new_str;
2546 for (pos++; pos < total_items; pos++) {
2547 tmp = (Items(spin))[pos];
2548 (Items(spin))[pos] = old;
2552 ItemCount(spin) = total_items;
2555 SetMaximumLabelSize(spin_p);
2556 if (Editable(spin) == FALSE) {
2557 ClearShadow(spin, TRUE);
2558 if (RecomputeSize(spin))
2559 SetSpinBoxSize(spin);
2560 LayoutChildren(spin);
2565 /* Update the text-field or label */
2567 SetTextFieldData(spin);
2577 DtSpinBoxDeletePos( Widget spinw,
2580 DtSpinBoxWidget spin = (DtSpinBoxWidget)spinw;
2581 DtSpinBoxPart *spin_p;
2583 _DtWidgetToAppContext(spinw);
2586 if (ItemCount(spin) < 1)
2592 spin_p = (DtSpinBoxPart*) &(XmField(spin,ipot,DtSpinBox,label,Widget));
2595 if ((pos < 0) || (pos > ItemCount(spin)))
2596 pos = ItemCount(spin) - 1;
2598 total_items = ItemCount(spin) - 1;
2599 XmStringFree((Items(spin))[pos]);
2601 /* To keep Position of SpinBox up to date */
2602 if (Position(spin) > 0 &&
2603 ((Position(spin) >= total_items) || pos < Position(spin)) )
2604 Position(spin) = Position(spin) - 1;
2606 if (pos < ItemCount(spin)) {
2607 for (; pos < total_items; pos++)
2608 (Items(spin))[pos] = (Items(spin))[pos+1];
2610 if (total_items > 0)
2611 Items(spin) = (XmString *)XtRealloc((char*)Items(spin),
2612 (sizeof(XmString) * total_items));
2614 XtFree((char *)Items(spin));
2615 Items(spin) = (XmString *)NULL;
2617 ItemCount(spin) = total_items;
2620 SetMaximumLabelSize(spin_p);
2621 if (Editable(spin) == FALSE) {
2622 ClearShadow(spin, TRUE);
2623 if (RecomputeSize(spin))
2624 SetSpinBoxSize(spin);
2625 LayoutChildren(spin);
2630 /* Update the text-field or label */
2632 SetTextFieldData(spin);
2640 * Make the given item the currently visible item in the
2641 * text-field or label.
2644 DtSpinBoxSetItem( Widget spinw,
2647 DtSpinBoxWidget spin = (DtSpinBoxWidget)spinw;
2649 _DtWidgetToAppContext(spinw);
2652 if (item && ItemCount(spin)>0) {
2653 for (i = 0; i < ItemCount(spin); i++)
2654 if (XmStringCompare(item, (Items(spin))[i]))
2656 if (i < ItemCount(spin)) {
2659 SetTextFieldData(spin);
2664 XtWarning(SB_SET_ITEM);
2667 XtWarning(SB_SET_ITEM);