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>
92 #include <Xm/RepType.h>
94 #include "DtWidgetI.h"
104 #define DtSpinBoxIndex (XmManagerIndex + 1)
105 static XmOffsetPtr ipot; /* Instance part offset table */
106 static XmOffsetPtr cpot; /* Constraint part offset table */
108 static void ClassInitialize ();
109 static void Initialize (DtSpinBoxWidget request,
110 DtSpinBoxWidget new, ArgList given_args,
112 static XmNavigability WidgetNavigable (DtSpinBoxWidget spin);
113 static void _SpinBoxFocusIn (DtSpinBoxWidget spin, XEvent *event,
114 char **params, Cardinal *num_params);
115 static void _SpinBoxFocusOut (DtSpinBoxWidget spin, XEvent *event,
116 char **params, Cardinal *num_params);
117 static void DrawHighlight (DtSpinBoxWidget spin, Boolean clear);
118 static void _SpinBoxUp (DtSpinBoxWidget spin,
119 XEvent *event, char **params,
120 Cardinal *num_params);
121 static void _SpinBoxDown (DtSpinBoxWidget spin,
122 XEvent *event, char **params,
123 Cardinal *num_params);
124 static void _SpinBoxLeft (DtSpinBoxWidget spin,
125 XEvent *event, char **params,
126 Cardinal *num_params);
127 static void _SpinBoxRight (DtSpinBoxWidget spin,
128 XEvent *event, char **params,
129 Cardinal *num_params);
130 static void _SpinBoxBeginLine (DtSpinBoxWidget spin,
131 XEvent *event, char **params,
132 Cardinal *num_params);
133 static void _SpinBoxEndLine (DtSpinBoxWidget spin,
134 XEvent *event, char **params,
135 Cardinal *num_params);
136 static void _SpinBoxGetFocus (DtSpinBoxWidget spin,
137 XEvent *event, char **params,
138 Cardinal *num_params);
139 static void _SpinBoxPrevTabGroup (DtSpinBoxWidget spin,
140 XEvent *event, char **params,
141 Cardinal *num_params);
142 static void _SpinBoxNextTabGroup (DtSpinBoxWidget spin,
143 XEvent *event, char **params,
144 Cardinal *num_params);
146 static void CheckResources (DtSpinBoxWidget spin);
147 static void Destroy (DtSpinBoxWidget spin);
148 static void Resize (DtSpinBoxWidget spin);
149 static void Redisplay (DtSpinBoxWidget w, XEvent *event,
151 static XtGeometryResult GeometryManager (Widget w,
152 XtWidgetGeometry *request,
153 XtWidgetGeometry *reply);
154 static void SetSpinBoxSize (DtSpinBoxWidget spin);
155 static void ForceChildSizes (DtSpinBoxWidget spin);
156 static void CalculateSizes (DtSpinBoxWidget spin,
159 Dimension *parrow_width);
160 static void LayoutChildren (DtSpinBoxWidget spin);
161 static Boolean SetValues (DtSpinBoxWidget current,
162 DtSpinBoxWidget request,
163 DtSpinBoxWidget new);
164 static void ClearShadow (DtSpinBoxWidget w, Boolean all);
165 static void DrawShadow (DtSpinBoxWidget w);
166 static void StoreResourceInfo (DtSpinBoxPart *spin_p,
167 DtSpinBoxPart *old_p,
169 static char* GetTextString (XmString xm_string);
170 static void SetTextFieldData (DtSpinBoxWidget spin);
171 static void SetMaximumLabelSize (DtSpinBoxPart *spin_p);
172 static void SetLabelData (DtSpinBoxWidget spin);
173 static void timer_dispatch (XtPointer client_data, XtIntervalId *id);
174 static void TextFieldActivate (DtSpinBoxPart *spin_p);
175 static Boolean SendCallback (DtSpinBoxWidget spin, XEvent *event,
176 Boolean value_changed, int position,
177 float current, Boolean crossed);
178 static void FinishUpDown (DtSpinBoxWidget spin,
179 XtPointer arrow_call_data, int new_position,
180 float new_current, Boolean crossed);
181 static void up_cb (Widget w, XtPointer client_data,
182 XtPointer call_data);
183 static void down_cb (Widget w, XtPointer client_data,
184 XtPointer call_data);
185 static void disarm_cb (Widget w, XtPointer client_data,
186 XtPointer call_data);
187 static void grab_leave_cb (Widget w, XtPointer client_data,
188 XEvent *event, Boolean *dispatch);
189 static void text_losing_focus_cb (Widget w, XtPointer client_data,
190 XtPointer call_data);
191 static void text_activate_cb (Widget w, XtPointer client_data,
192 XtPointer call_data);
193 static void text_focus_cb (Widget w, XtPointer client_data,
194 XtPointer call_data);
195 static XmImportOperator _XmSetSyntheticResForChild (Widget widget,
199 static XmString InitLabel = NULL;
204 #define Label(w) XmField(w,ipot,DtSpinBox,label,Widget)
205 #define UpArrow(w) XmField(w,ipot,DtSpinBox,up_arrow,Widget)
206 #define DownArrow(w) XmField(w,ipot,DtSpinBox,down_arrow,Widget)
207 #define WhichArrow(w) XmField(w,ipot,DtSpinBox,which_arrow,unsigned char)
208 #define InitCb(w) XmField(w,ipot,DtSpinBox,init_cb,Boolean)
209 #define Grabbed(w) XmField(w,ipot,DtSpinBox,grabbed,Boolean)
210 #define Base(w) XmField(w,ipot,DtSpinBox,base,int)
211 #define Min(w) XmField(w,ipot,DtSpinBox,min,float)
212 #define Max(w) XmField(w,ipot,DtSpinBox,max,float)
213 #define Increment(w) XmField(w,ipot,DtSpinBox,increment,float)
214 #define Current(w) XmField(w,ipot,DtSpinBox,current,float)
215 #define FloatFormat(w) (String) &(XmField(w,ipot,DtSpinBox,float_format,char *))
216 #define OldWidth(w) XmField(w,ipot,DtSpinBox,old_width,Dimension)
217 #define OldHeight(w) XmField(w,ipot,DtSpinBox,old_height,Dimension)
218 #define LabelMaxLength(w) XmField(w,ipot,DtSpinBox,label_max_length,Dimension)
219 #define LabelMaxHeight(w) XmField(w,ipot,DtSpinBox,label_max_height,Dimension)
221 #define ArrowSensitivity(w) XmField(w,ipot,DtSpinBox,arrow_sensitivity,unsigned char)
222 #define DecimalPoints(w) XmField(w,ipot,DtSpinBox,decimal_points,short)
223 #define NumericIncrement(w) XmField(w,ipot,DtSpinBox,numeric_increment,int)
224 #define Maximum(w) XmField(w,ipot,DtSpinBox,maximum,int)
225 #define Minimum(w) XmField(w,ipot,DtSpinBox,minimum,int)
226 #define ItemCount(w) XmField(w,ipot,DtSpinBox,item_count,int)
227 #define Position(w) XmField(w,ipot,DtSpinBox,position,int)
228 #define ChildType(w) XmField(w,ipot,DtSpinBox,child_type,unsigned char)
229 #define Items(w) XmField(w,ipot,DtSpinBox,items,XmStringTable)
230 #define ActivateCallback(w) XmField(w,ipot,DtSpinBox,activate_callback,XtCallbackList)
231 #define Alignment(w) XmField(w,ipot,DtSpinBox,alignment,unsigned char)
232 #define ArrowLayout(w) XmField(w,ipot,DtSpinBox,arrow_layout,unsigned char)
233 #define ArrowSize(w) XmField(w,ipot,DtSpinBox,arrow_size,Dimension)
234 #define TextColumns(w) XmField(w,ipot,DtSpinBox,text_columns,short)
235 #define Editable(w) XmField(w,ipot,DtSpinBox,editable,Boolean)
236 #define FocusCallback(w) XmField(w,ipot,DtSpinBox,focus_callback,XtCallbackList)
237 #define InitialDelay(w) XmField(w,ipot,DtSpinBox,initial_delay,unsigned int)
238 #define LosingFocusCallback(w) XmField(w,ipot,DtSpinBox,losing_focus_callback,XtCallbackList)
239 #define MarginHeight(w) XmField(w,ipot,DtSpinBox,margin_height,Dimension)
240 #define MarginWidth(w) XmField(w,ipot,DtSpinBox,margin_width,Dimension)
241 #define TextMaxLength(w) XmField(w,ipot,DtSpinBox,text_max_length,int)
242 #define ModifyVerifyCallback(w) XmField(w,ipot,DtSpinBox,modify_verify_callback,XtCallbackList)
243 #define RecomputeSize(w) XmField(w,ipot,DtSpinBox,recompute_size,Boolean)
244 #define RepeatDelay(w) XmField(w,ipot,DtSpinBox,repeat_delay,unsigned int)
245 #define Text(w) XmField(w,ipot,DtSpinBox,text,Widget)
246 #define ValueChangedCallback(w) XmField(w,ipot,DtSpinBox,value_changed_callback,XtCallbackList)
247 #define Wrap(w) XmField(w,ipot,DtSpinBox,wrap,Boolean)
248 #define Timer(w) XmField(w,ipot,DtSpinBox,timer,XtIntervalId)
250 /* SpinBox and Superclass resource macros*/
251 #define PUnitType(w) w->primitive.unit_type
252 #define MUnitType(w) w->manager.unit_type
253 #define MFgPixel(w) w->manager.foreground
254 #define SPIN_SHADOW(w) w->manager.shadow_thickness
255 #define CBgPixel(w) w->core.background_pixel
256 #define CBgPixmap(w) w->core.background_pixmap
257 #define Width(w) w->core.width
258 #define Height(w) w->core.height
259 #define SPIN_MARGIN_W(w) MarginWidth(w)
260 #define SPIN_MARGIN_H(w) MarginHeight(w)
261 #define MAXINT 2147483647 /* Taken from TextF.c */
262 #define DEFAULT_COL 20
264 /* USL: Label get Focus */
265 static XtTranslations child_trans_label;
266 /* USL: Keyboard only for Text */
267 static XtTranslations child_trans_text;
268 static XtTranslations child_trans_arrow;
270 static XtTranslations child_trans;
271 static XtTranslations spin_trans;
274 static char const SpinBoxTranslationTable[] = "\
275 <FocusIn>: SpinBoxFocusIn() \n\
276 <FocusOut>: SpinBoxFocusOut() \n\
277 <Key>osfUp: SpinBoxUp() \n\
278 <Key>osfDown: SpinBoxDown() \n\
279 <Key>osfRight: SpinBoxRight() \n\
280 <Key>osfLeft: SpinBoxLeft() \n\
281 <Key>osfBeginLine: SpinBoxBeginLine() \n\
282 <Key>osfEndLine: SpinBoxEndLine() \n\
285 static char const SpinBoxChildTranslationTable[] = "\
286 <Key>osfUp: SpinBoxUp(child) \n\
287 <Key>osfDown: SpinBoxDown(child) \n\
288 <Key>osfRight: SpinBoxRight(child) \n\
289 <Key>osfLeft: SpinBoxLeft(child) \n\
290 <Key>osfBeginLine: SpinBoxBeginLine(child) \n\
291 <Key>osfEndLine: SpinBoxEndLine(child) \n\
294 /* #5: Label get focus */
295 static char const SpinBoxLabelTranslationTable[] = "\
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 <Key>osfDown: SpinBoxGetFocus() \n\
303 <Btn1Down>,<Btn1Up>: SpinBoxGetFocus() \n\
304 <Key>osfSelect: SpinBoxGetFocus() \n\
305 ~s ~m ~a <Key>space: SpinBoxGetFocus() \n\
308 /* USL: Keyboard Only Traversing During Editable-Mode */
309 static char const SpinBoxTextTranslationTable[] = "\
310 <Key>osfUp: SpinBoxUp(child) SpinBoxRight(child)\n\
311 <Key>osfDown: SpinBoxDown(child) SpinBoxLeft(child)\n\
313 static char const SpinBoxArrowTranslationTable[] = "\
314 <Key>osfUp: SpinBoxUp(child) \n\
315 <Key>osfDown: SpinBoxDown(child) \n\
316 <Key>osfRight: SpinBoxRight(child) \n\
317 <Key>osfLeft: SpinBoxLeft(child) \n\
318 <Key>osfBeginLine: SpinBoxBeginLine(child) \n\
319 <Key>osfEndLine: SpinBoxEndLine(child) \n\
320 s ~m ~a <Key>Tab: SpinBoxPrevTabGroup()\n\
321 ~m ~a <Key>Tab: SpinBoxNextTabGroup()\n\
325 static XtActionsRec SpinBoxActionTable[] = {
326 {"SpinBoxFocusIn", (XtActionProc)_SpinBoxFocusIn},
327 {"SpinBoxFocusOut", (XtActionProc)_SpinBoxFocusOut},
328 {"SpinBoxUp", (XtActionProc)_SpinBoxUp},
329 {"SpinBoxDown", (XtActionProc)_SpinBoxDown},
330 {"SpinBoxRight", (XtActionProc)_SpinBoxRight},
331 {"SpinBoxLeft", (XtActionProc)_SpinBoxLeft},
332 {"SpinBoxBeginLine", (XtActionProc)_SpinBoxBeginLine},
333 {"SpinBoxEndLine", (XtActionProc)_SpinBoxEndLine},
334 {"SpinBoxGetFocus", (XtActionProc)_SpinBoxGetFocus},
335 {"SpinBoxPrevTabGroup", (XtActionProc)_SpinBoxPrevTabGroup},
336 {"SpinBoxNextTabGroup", (XtActionProc)_SpinBoxNextTabGroup},
339 /* DtSpinBoxWidget resources */
341 #define offset(field) XtOffset(DtSpinBoxWidget, field)
342 #define DtOffset(field) XmPartOffset(DtSpinBox,field)
343 static XmPartResource resources[] = {
344 {XmNshadowThickness, XmCShadowThickness, XmRHorizontalDimension,
345 sizeof(Dimension), offset(manager.shadow_thickness),
346 XmRImmediate, (XtPointer)TEXT_FIELD_SHADOW},
348 /* Common resources */
349 {DtNactivateCallback, DtCCallback, XmRCallback, sizeof(XtCallbackList),
350 DtOffset(activate_callback), XmRCallback,
352 {DtNalignment, DtCAlignment, XmRAlignment, sizeof(unsigned char),
353 DtOffset(alignment), XmRImmediate,
354 (XtPointer)DtALIGNMENT_BEGINNING},
355 {DtNarrowLayout, DtCArrowLayout, DtRArrowLayout, sizeof(unsigned char),
356 DtOffset(arrow_layout), XmRImmediate,
357 (XtPointer)DtARROWS_END},
358 {DtNarrowSensitivity, DtCArrowSensitivity, DtRArrowSensitivity,
359 sizeof(unsigned char), DtOffset(arrow_sensitivity),
360 XmRImmediate, (XtPointer)DtARROWS_SENSITIVE},
361 {DtNspinBoxChildType, DtCSpinBoxChildType, DtRSpinBoxChildType,
362 sizeof(unsigned char),
363 DtOffset(child_type), XmRImmediate, (XtPointer)DtSTRING},
364 {DtNcolumns, DtCColumns, XmRShort, sizeof(short),
365 DtOffset(text_columns), XmRImmediate, (XtPointer)DEFAULT_COL},
366 {DtNdecimalPoints, DtCDecimalPoints, XmRShort, sizeof( short ),
367 DtOffset(decimal_points), XmRImmediate, (XtPointer)0},
368 {DtNeditable, DtCEditable, XmRBoolean, sizeof(Boolean),
369 DtOffset(editable), XmRImmediate, (XtPointer)TRUE},
370 {DtNfocusCallback, DtCCallback, XmRCallback, sizeof(XtCallbackList),
371 DtOffset(focus_callback), XmRCallback,
373 {DtNincrementValue, DtCIncrementValue, XmRInt, sizeof(int),
374 DtOffset(numeric_increment), XmRImmediate, (XtPointer)1},
375 {DtNinitialDelay, DtCInitialDelay, XmRInt, sizeof(unsigned int),
376 DtOffset(initial_delay), XmRImmediate, (XtPointer)250},
377 {DtNnumValues, DtCNumValues, DtRNumValues, sizeof(int),
378 DtOffset(item_count), XmRImmediate, (XtPointer)0},
379 {DtNvalues, DtCItems, XmRXmStringTable, sizeof(XmStringTable),
380 DtOffset(items), XmRImmediate, (XtPointer)NULL},
381 {DtNlosingFocusCallback, DtCCallback, XmRCallback, sizeof(XtCallbackList),
382 DtOffset(losing_focus_callback), XmRCallback,
384 {DtNmarginHeight, DtCMarginHeight, XmRVerticalDimension, sizeof(Dimension),
385 DtOffset(margin_height), XmRImmediate, (XtPointer)MARGIN},
386 {DtNmarginWidth, DtCMarginWidth, XmRHorizontalDimension, sizeof(Dimension),
387 DtOffset(margin_width), XmRImmediate, (XtPointer)MARGIN},
388 {DtNmaximumValue, DtCMaximumValue, XmRInt, sizeof(int),
389 DtOffset(maximum), XmRImmediate, (XtPointer)10},
390 {DtNmaxLength, DtCMaxLength, XmRInt, sizeof(int),
391 DtOffset(text_max_length), XmRImmediate, (XtPointer)MAXINT},
392 {DtNminimumValue, DtCMinimumValue, XmRInt, sizeof(int),
393 DtOffset(minimum), XmRImmediate, (XtPointer)0},
394 {DtNmodifyVerifyCallback, DtCCallback, XmRCallback,
395 sizeof(XtCallbackList), DtOffset(modify_verify_callback),
396 XmRCallback, (XtPointer)NULL},
397 {DtNposition, DtCPosition, XmRInt, sizeof(int),
398 DtOffset(position), XmRImmediate, (XtPointer)0},
399 {DtNrecomputeSize, DtCRecomputeSize, XmRBoolean, sizeof(Boolean),
400 DtOffset(recompute_size), XmRImmediate, (XtPointer)TRUE},
401 {DtNrepeatDelay, DtCRepeatDelay, XmRInt, sizeof(unsigned int),
402 DtOffset(repeat_delay), XmRImmediate, (XtPointer)200},
403 {DtNtextField, DtCTextField, XmRWidget, sizeof(Widget),
404 DtOffset(text), XmRImmediate, (XtPointer)NULL},
405 {DtNvalueChangedCallback, DtCCallback, XmRCallback,
406 sizeof(XtCallbackList), DtOffset(value_changed_callback),
407 XmRCallback, (XtPointer)NULL},
408 {DtNwrap, DtCWrap, XmRBoolean, sizeof(Boolean),
409 DtOffset(wrap), XmRImmediate, (XtPointer)TRUE},
412 /* Synthetic resources. Only used for Motif API arrowSize right now */
413 static XmSyntheticResource syn_resources[] = {
414 {DtNarrowSize, sizeof(Dimension), DtOffset(arrow_size),
415 _DtSpinBoxGetArrowSize, _XmSetSyntheticResForChild},
416 {DtNmarginHeight, sizeof(Dimension), DtOffset(margin_height),
417 XmeFromVerticalPixels, XmeToVerticalPixels},
418 {DtNmarginWidth, sizeof(Dimension), DtOffset(margin_width),
419 XmeFromHorizontalPixels, XmeToHorizontalPixels},
424 /* Need Class Extension for widget navigation */
425 static XmBaseClassExtRec baseClassExtRec = {
428 XmBaseClassExtVersion,
429 sizeof(XmBaseClassExtRec),
430 (XtInitProc)NULL, /* InitializePrehook */
431 (XtSetValuesFunc)NULL, /* SetValuesPrehook */
432 (XtInitProc)NULL, /* InitializePosthook */
433 (XtSetValuesFunc)NULL, /* SetValuesPosthook */
434 NULL, /* secondaryObjectClass */
435 (XtInitProc)NULL, /* secondaryCreate */
436 (XmGetSecResDataFunc)NULL, /* getSecRes data */
437 { 0 }, /* fastSubclass flags */
438 (XtArgsProc)NULL, /* getValuesPrehook */
439 (XtArgsProc)NULL, /* getValuesPosthook */
440 (XtWidgetClassProc)NULL, /* classPartInitPrehook */
441 (XtWidgetClassProc)NULL, /* classPartInitPosthook*/
442 NULL, /* ext_resources */
443 NULL, /* compiled_ext_resources*/
444 0, /* num_ext_resources */
445 FALSE, /* use_sub_resources */
446 (XmWidgetNavigableProc)WidgetNavigable,
447 /* widgetNavigable */
448 (XmFocusChangeProc)NULL, /* focusChange */
449 (XmWrapperData)NULL /* wrapperData */
453 * Define Class Record.
455 externaldef(dtspinboxclassrec) DtSpinBoxClassRec dtSpinBoxClassRec =
457 { /* core_class fields */
458 (WidgetClass)&(xmManagerClassRec), /* superclass */
459 (String)"DtSpinBox", /* class_name */
460 (Cardinal)sizeof(DtSpinBoxPart), /* widget_size */
461 (XtProc)ClassInitialize, /* class_initialize */
462 (XtWidgetClassProc)NULL, /* class_part_init */
463 (XtEnum)FALSE, /* class_inited */
464 (XtInitProc)Initialize, /* initialize */
465 (XtArgsProc)NULL, /* initialize_hook */
466 (XtRealizeProc)XtInheritRealize, /* realize */
467 (XtActionList)SpinBoxActionTable, /* actions */
468 (Cardinal)XtNumber(SpinBoxActionTable), /* num_actions */
469 (XtResourceList)resources, /* resources */
470 (Cardinal)XtNumber(resources), /* num_resources */
471 (XrmClass)NULLQUARK, /* xrm_class */
472 (Boolean)TRUE, /* compress_motion */
473 (XtEnum)XtExposeCompressMaximal, /* compress_exposure */
474 (Boolean)TRUE, /* compress_enterleave*/
475 (Boolean)FALSE, /* visible_interest */
476 (XtWidgetProc)Destroy, /* destroy */
477 (XtWidgetProc)Resize, /* resize */
478 (XtExposeProc)Redisplay, /* expose */
479 (XtSetValuesFunc)SetValues, /* set_values */
480 (XtArgsFunc)NULL, /* set values hook */
481 (XtAlmostProc)XtInheritSetValuesAlmost, /* set values almost */
482 (XtArgsProc)NULL, /* get values hook */
483 (XtAcceptFocusProc)NULL, /* accept_focus */
484 (XtVersionType)XtVersionDontCheck, /* Version */
485 (XtPointer)NULL, /* PRIVATE cb list */
486 (String)XtInheritTranslations, /* tm_table */
487 (XtGeometryHandler)XtInheritQueryGeometry, /* query_geom */
488 (XtStringProc)XtInheritDisplayAccelerator, /* display_accelerator*/
489 (XtPointer)&baseClassExtRec /* extension */
491 { /* composite_class fields */
492 (XtGeometryHandler)GeometryManager, /* geometry_manager */
493 (XtWidgetProc)XtInheritChangeManaged, /* change_managed */
494 (XtWidgetProc)XtInheritInsertChild, /* insert_child */
495 (XtWidgetProc)XtInheritDeleteChild, /* delete_child */
496 (XtPointer)NULL /* extension */
498 { /* constraint_class fields */
499 (XtResourceList)NULL, /* resources */
500 (Cardinal)0, /* num_resources */
501 (Cardinal)0, /* constraint_size */
502 (XtInitProc)NULL, /* initialize */
503 (XtWidgetProc)NULL, /* destroy */
504 (XtSetValuesFunc)NULL, /* set_values */
505 (XtPointer)NULL /* extension */
507 { /* manager class */
508 (String)XtInheritTranslations, /* translations */
509 (XmSyntheticResource*)syn_resources, /* syn resources */
510 (int)XtNumber(syn_resources), /* num syn_resources */
511 (XmSyntheticResource*)NULL, /* get_cont_resources */
512 (int)0, /* num_get_cont_resources */
513 (XmParentProcessProc)XmInheritParentProcess,/* parent_process */
514 (XtPointer)NULL /* extension */
516 { /* spin_box_class fields */
521 externaldef(dtspinboxwidgetclass) WidgetClass dtSpinBoxWidgetClass =
522 (WidgetClass)&dtSpinBoxClassRec;
524 static XmRepTypeId _DtRID_SB_ARROW_SENSITIVITY_TYPE;
525 static String _DtArrowSensitivityNames[] = {
526 "arrows_insensitive",
527 "arrows_increment_sensitive",
528 "arrows_decrement_sensitive",
533 * Must set up the record type for the class extensions to work.
536 ClassInitialize(void)
538 baseClassExtRec.record_type = XmQmotif;
542 XmResolveAllPartOffsets(dtSpinBoxWidgetClass, &ipot, &cpot);
544 child_trans = XtParseTranslationTable(SpinBoxChildTranslationTable);
545 spin_trans = XtParseTranslationTable(SpinBoxTranslationTable);
547 child_trans_label=XtParseTranslationTable(SpinBoxLabelTranslationTable);
548 child_trans_text=XtParseTranslationTable(SpinBoxTextTranslationTable);
549 child_trans_arrow=XtParseTranslationTable(SpinBoxArrowTranslationTable);
551 _DtRID_SB_ARROW_SENSITIVITY_TYPE =
552 XmRepTypeRegister(DtRArrowSensitivity, _DtArrowSensitivityNames,
553 NULL, XtNumber(_DtArrowSensitivityNames));
555 InitLabel = XmStringCreateLocalized(SB_LABEL);
559 * SpinBox initialization function. This builds the widgets inside
560 * our widget, to get the correct layout. If the editable resource
561 * is TRUE, we create a textField; if FALSE, we create a label. If the
562 * user changes this resource later, we will create the other widget
563 * (textField or Label). We don't want to carry backage from both
564 * widgets if the user never changes the editable resource.
567 Initialize( DtSpinBoxWidget request,
572 DtSpinBoxPart *spin_p = (DtSpinBoxPart*)
573 &(XmField(new,ipot,DtSpinBox,label,Widget));
578 /* Resolution Independent */
579 unsigned char unit_type = MUnitType(new);
581 /* Overwrite the manager's focusIn and focusOut translations */
582 XtOverrideTranslations((Widget)new, spin_trans);
584 widget_name = XtMalloc(strlen(XtName((Widget)new)) + 10);
586 Text(new) = (Widget)NULL;
587 Label(new) = (Widget)NULL;
591 Grabbed(new) = FALSE;
596 * Create the text or label depending on editable resource.
599 sprintf(widget_name, "%s_TF", XtName((Widget)new));
601 XtSetArg(args[n], XmNmaxLength, TextMaxLength(new)); n++;
602 XtSetArg(args[n], XmNmarginWidth, TEXT_CONTEXT_MARGIN); n++;
603 XtSetArg(args[n], XmNmarginHeight, 2); n++;
604 /* Resolution Independent */
605 if (unit_type != XmPIXELS) {
606 XtSetArg(args[n], XmNunitType, XmPIXELS); n++;
608 Text(new) = XtCreateManagedWidget(widget_name,
609 xmTextFieldWidgetClass,
610 (Widget)new, args, n);
611 XtAddCallback(Text(new), XmNlosingFocusCallback,
612 text_losing_focus_cb, (XtPointer)new);
613 XtAddCallback(Text(new), XmNactivateCallback,
614 text_activate_cb, (XtPointer)new);
615 XtAddCallback(Text(new), XmNfocusCallback,
616 text_focus_cb, (XtPointer)new);
618 XtOverrideTranslations((Widget)Text(new), child_trans_text);
620 if (TextColumns(request) == DEFAULT_COL && Width(request)) {
622 CalculateSizes(new, &width, NULL, NULL);
623 XtSetArg(args[n], XmNwidth, width); n++;
626 XtSetArg(args[n], XmNcolumns, TextColumns(new)); n++;
628 if (unit_type != XmPIXELS) {
629 XtSetArg(args[n], XmNunitType, unit_type); n++;
631 XtSetValues(Text(new), args, n);
634 sprintf(widget_name, "%s_Label", XtName((Widget)new));
635 SPIN_SHADOW(new) = LABEL_SHADOW;
637 XtSetArg(args[n], XmNalignment, Alignment(new)); n++;
638 XtSetArg(args[n], XmNrecomputeSize, FALSE); n++;
639 XtSetArg(args[n], XmNlabelString, InitLabel); n++;
640 XtSetArg(args[n], XmNmarginLeft, LABEL_PADDING); n++;
641 XtSetArg(args[n], XmNmarginRight, LABEL_PADDING); n++;
642 XtSetArg(args[n], XmNmarginWidth, TEXT_CONTEXT_MARGIN); n++;
643 XtSetArg(args[n], XmNmarginHeight, 2); n++;
644 if (unit_type != XmPIXELS) {
645 XtSetArg(args[n], XmNunitType, XmPIXELS); n++;
647 Label(new) = XtCreateManagedWidget(widget_name, xmLabelWidgetClass,
648 (Widget)new, args, n);
650 XtOverrideTranslations((Widget)Label(new), child_trans_label);
652 if (unit_type != XmPIXELS) {
653 XtSetArg(args[n], XmNunitType, unit_type); n++;
657 CalculateSizes(new, &width, NULL, NULL);
658 XtSetArg(args[n], XmNwidth, width); n++;
661 XtSetValues(Label(new), args, n);
665 * Create the 2 ArrowWidgets.
667 sprintf(widget_name, "%s_Up", XtName((Widget)new));
669 if (ArrowLayout(new) == DtARROWS_SPLIT) {
670 XtSetArg(args[n], XmNarrowDirection, XmARROW_RIGHT); n++;
672 XtSetArg(args[n], XmNhighlightThickness, 0); n++;
673 XtSetArg(args[n], XmNshadowThickness, 0); n++;
674 XtSetArg(args[n], XmNtraversalOn, FALSE); n++;
675 XtSetArg(args[n], XmNforeground, CBgPixel(new)); n++;
676 UpArrow(new) = XtCreateManagedWidget(widget_name,
677 xmArrowButtonWidgetClass,
678 (Widget)new, args, n);
679 XtOverrideTranslations((Widget)UpArrow(new), child_trans_arrow);
681 sprintf(widget_name, "%s_Down", XtName((Widget)new));
682 if (ArrowLayout(new) == DtARROWS_SPLIT) {
683 XtSetArg(args[n], XmNarrowDirection, XmARROW_LEFT); n++;
686 XtSetArg(args[n], XmNarrowDirection, XmARROW_DOWN); n++;
688 DownArrow(new) = XtCreateManagedWidget(widget_name,
689 xmArrowButtonWidgetClass,
690 (Widget)new, args, n);
691 XtOverrideTranslations((Widget)DownArrow(new), child_trans_arrow);
693 /* Set sensitivity of arrows (up arrow is right arrow) */
694 if ((ArrowSensitivity(new) == DtARROWS_INSENSITIVE) ||
695 (ArrowSensitivity(new) == DtARROWS_DECREMENT_SENSITIVE))
696 XtSetSensitive(UpArrow(new), FALSE);
697 if ((ArrowSensitivity(new) == DtARROWS_INSENSITIVE) ||
698 (ArrowSensitivity(new) == DtARROWS_INCREMENT_SENSITIVE))
699 XtSetSensitive(DownArrow(new), FALSE);
702 * Arm causes the value to change and the timer to start.
703 * Disarm (leaveNotify from grab) causes the timer to stop.
705 XtAddCallback(UpArrow(new), XmNarmCallback, up_cb, (XtPointer)new);
706 XtAddCallback(UpArrow(new), XmNdisarmCallback, disarm_cb,
708 XtAddEventHandler(UpArrow(new), LeaveWindowMask, FALSE, grab_leave_cb,
710 XtAddCallback(DownArrow(new), XmNarmCallback, down_cb, (XtPointer)new);
711 XtAddCallback(DownArrow(new), XmNdisarmCallback, disarm_cb,
713 XtAddEventHandler(DownArrow(new), LeaveWindowMask, FALSE,
714 grab_leave_cb, (XtPointer)new);
716 /* Initialize everything based on what the resource values are */
717 StoreResourceInfo(spin_p, NULL, TRUE);
720 * Set initial value in text or label if items was specified
722 if (Editable(new) == FALSE) {
724 SetMaximumLabelSize(spin_p);
728 SetTextFieldData(new);
734 /* Store Converter for DtNmaximumValue, DtNminimumValue, DtNincrementValue,
736 XtSetTypeConverter(XmRString, DtRMaximumValue, XtCvtStringToInt, NULL, 0,
738 XtSetTypeConverter(XmRString, DtRMinimumValue, XtCvtStringToInt, NULL, 0,
740 XtSetTypeConverter(XmRString, DtRIncrementValue, XtCvtStringToInt, NULL, 0,
742 XtSetTypeConverter(XmRString, DtRNumValues, XtCvtStringToInt, NULL, 0,
745 * this is so these resources can be set uniformly through XtCreateWidget
746 * or through defaults file as *spin.backgound
750 XtSetArg(args[n],XmNbackground,CBgPixel(new));n++;
751 XtSetArg(args[n],XmNbackgroundPixmap,CBgPixmap(new));n++;
752 XtSetArg(args[n],XmNforeground,MFgPixel(new));n++;
754 XtSetValues (Text(new),args,n);
756 XtSetValues (Label(new),args,n);
758 XtSetValues (UpArrow(new),args,n);
760 XtSetValues (DownArrow(new),args,n);
766 * Allow the manager to gain focus if not editable. If editable (using
767 * text-field), then let the toolkit give focus to the text-field.
769 static XmNavigability
770 WidgetNavigable(DtSpinBoxWidget spin)
772 XmNavigationType nav_type = ((XmManagerWidget)spin)->manager.navigation_type;
774 if (spin->core.sensitive && spin->core.ancestor_sensitive &&
775 ((XmManagerWidget)spin)->manager.traversal_on) {
776 if ((nav_type == XmSTICKY_TAB_GROUP) ||
777 (nav_type == XmEXCLUSIVE_TAB_GROUP) ||
778 ((nav_type == XmTAB_GROUP) &&
779 !_XmShellIsExclusive((Widget)spin))) {
781 return(XmDESCENDANTS_TAB_NAVIGABLE);
783 return(XmTAB_NAVIGABLE);
785 return(XmDESCENDANTS_NAVIGABLE);
787 return(XmNOT_NAVIGABLE);
791 * The spin_box gets focus.
794 _SpinBoxFocusIn( DtSpinBoxWidget spin,
797 Cardinal *num_params)
799 DrawHighlight(spin, FALSE);
803 * The spin_box loses focus.
806 _SpinBoxFocusOut( DtSpinBoxWidget spin,
809 Cardinal *num_params)
811 DrawHighlight(spin, TRUE);
815 * This function gets called whenever we draw or clear the shadow (to
816 * redraw highlight during resize, etc), as well as during focus_in
817 * and focus_out events.
820 DrawHighlight( DtSpinBoxWidget spin,
825 if (XtIsRealized((Widget)spin)) {
827 rect[0].x = rect[1].x = rect[2].x = 0;
828 rect[3].x = OldWidth(spin) - SPIN_MARGIN_W(spin);
829 rect[0].y = rect[2].y = rect[3].y = 0 ;
830 rect[1].y = OldHeight(spin) - SPIN_MARGIN_H(spin);
831 rect[0].width = rect[1].width = OldWidth(spin);
832 rect[2].width = rect[3].width = SPIN_MARGIN_W(spin);
833 rect[0].height = rect[1].height = SPIN_MARGIN_H(spin);
834 rect[2].height = rect[3].height = OldHeight(spin);
835 XFillRectangles(XtDisplayOfObject((Widget)spin),
836 XtWindowOfObject((Widget)spin),
837 spin->manager.background_GC, rect, 4);
839 else if (XmGetFocusWidget((Widget)spin) == (Widget)spin) {
840 rect[0].x = rect[1].x = rect[2].x = 0;
841 rect[3].x = XtWidth(spin) - SPIN_MARGIN_W(spin);
842 rect[0].y = rect[2].y = rect[3].y = 0 ;
843 rect[1].y = XtHeight(spin) - SPIN_MARGIN_H(spin);
844 rect[0].width = rect[1].width = XtWidth(spin);
845 rect[2].width = rect[3].width = SPIN_MARGIN_W(spin);
846 rect[0].height = rect[1].height = SPIN_MARGIN_H(spin);
847 rect[2].height = rect[3].height = XtHeight(spin);
848 XFillRectangles(XtDisplayOfObject((Widget)spin),
849 XtWindowOfObject((Widget)spin),
850 spin->manager.highlight_GC, rect, 4);
857 * osfUp virtual key hit. Simulate hitting the up arrow.
860 _SpinBoxUp( DtSpinBoxWidget spin,
863 Cardinal *num_params)
865 if (*num_params != 0) /* params means label or arrows */
866 spin = (DtSpinBoxWidget)XtParent(spin);
868 if (ArrowLayout(spin) != DtARROWS_SPLIT) {
869 up_cb((Widget)UpArrow(spin), (XtPointer)spin, NULL);
870 disarm_cb((Widget)UpArrow(spin), (XtPointer)spin, NULL);
875 * osfDown virtual key hit. Simulate hitting the down arrow.
878 _SpinBoxDown(DtSpinBoxWidget spin,
881 Cardinal *num_params)
883 if (*num_params != 0) /* params means label or arrows */
884 spin = (DtSpinBoxWidget)XtParent(spin);
886 if (ArrowLayout(spin) != DtARROWS_SPLIT) {
887 down_cb((Widget)DownArrow(spin), (XtPointer)spin, NULL);
888 disarm_cb((Widget)DownArrow(spin), (XtPointer)spin, NULL);
893 * osfRight virtual key hit. Simulate hitting the up arrow.
896 _SpinBoxRight(DtSpinBoxWidget spin,
899 Cardinal *num_params)
901 if (*num_params != 0) /* params means label or arrows */
902 spin = (DtSpinBoxWidget)XtParent(spin);
904 if (ArrowLayout(spin) == DtARROWS_SPLIT) {
905 up_cb((Widget)UpArrow(spin), (XtPointer)spin, NULL);
906 disarm_cb((Widget)UpArrow(spin), (XtPointer)spin, NULL);
911 * osfLeft virtual key hit. Simulate hitting the down arrow.
914 _SpinBoxLeft(DtSpinBoxWidget spin,
917 Cardinal *num_params)
919 if (*num_params != 0) /* params means label or arrows */
920 spin = (DtSpinBoxWidget)XtParent(spin);
922 if (ArrowLayout(spin) == DtARROWS_SPLIT) {
923 down_cb((Widget)DownArrow(spin), (XtPointer)spin, NULL);
924 disarm_cb((Widget)DownArrow(spin), (XtPointer)spin, NULL);
929 * osfBeginLine virtual key hit. Go to first item.
932 _SpinBoxBeginLine( DtSpinBoxWidget spin,
935 Cardinal *num_params)
940 if (*num_params != 0) /* params means label or arrows */
941 spin = (DtSpinBoxWidget)XtParent(spin);
943 if (ChildType(spin) == DtNUMERIC) {
944 new_position = Minimum(spin);
945 new_current = Min(spin);
950 if (SendCallback(spin, event, FALSE, new_position,
951 new_current, FALSE) == TRUE) {
952 /* User said yes, so set widget values */
953 Position(spin) = new_position;
954 Current(spin) = new_current;
956 SetTextFieldData(spin);
960 /* send value_changed callback */
961 (void)SendCallback(spin, event, TRUE, Position(spin),
962 Current(spin), FALSE);
967 * osfEndLine virtual key hit. Go to last item.
970 _SpinBoxEndLine( DtSpinBoxWidget spin,
973 Cardinal *num_params)
978 if (*num_params != 0) /* params means label or arrows */
979 spin = (DtSpinBoxWidget)XtParent(spin);
981 if (ChildType(spin) == DtNUMERIC) {
982 new_position = Maximum(spin);
983 new_current = Max(spin);
986 new_position = ItemCount(spin) - 1;
988 if (SendCallback(spin, event, FALSE, new_position,
989 new_current, FALSE) == TRUE) {
990 /* User said yes, so set widget values */
991 Position(spin) = new_position;
992 Current(spin) = new_current;
994 SetTextFieldData(spin);
998 /* send value_changed callback */
999 (void)SendCallback(spin, event, TRUE, Position(spin),
1000 Current(spin), FALSE);
1005 * USL: Get Focus for SpinBox when hit its label part
1008 _SpinBoxGetFocus( DtSpinBoxWidget spin,
1011 Cardinal *num_params)
1013 XmProcessTraversal((Widget)XtParent(spin),
1014 (XmTraversalDirection) XmTRAVERSE_CURRENT);
1018 * USL: Process Focus Traversal for SpinBox when cursor is in its arrow part
1021 _SpinBoxPrevTabGroup(DtSpinBoxWidget spin,
1024 Cardinal *num_params)
1026 XmProcessTraversal((Widget)XtParent(spin),
1027 (XmTraversalDirection) XmTRAVERSE_PREV_TAB_GROUP);
1031 _SpinBoxNextTabGroup(DtSpinBoxWidget spin,
1034 Cardinal *num_params)
1036 XmProcessTraversal((Widget)XtParent(spin),
1037 (XmTraversalDirection) XmTRAVERSE_NEXT_TAB_GROUP);
1041 * This function goes through most of the resources and makes sure
1042 * they have legal values.
1045 CheckResources(DtSpinBoxWidget spin)
1047 if (!XmRepTypeValidValue(_DtRID_SB_ARROW_SENSITIVITY_TYPE,
1048 ArrowSensitivity(spin), (Widget)spin)) {
1049 XtWarning(SB_ARROW_SENSITIVE);
1050 ArrowSensitivity(spin) = DtARROWS_SENSITIVE;
1052 if ((Alignment(spin) != DtALIGNMENT_CENTER) &&
1053 (Alignment(spin) != DtALIGNMENT_BEGINNING) &&
1054 (Alignment(spin) != DtALIGNMENT_END)) {
1055 XtWarning(SB_ALIGNMENT);
1056 Alignment(spin) = DtALIGNMENT_CENTER;
1058 if (InitialDelay(spin) == 0) {
1059 XtWarning(SB_INIT_DELAY);
1060 InitialDelay(spin) = 250;
1062 if ((ArrowLayout(spin) != DtARROWS_FLAT_BEGINNING) &&
1063 (ArrowLayout(spin) != DtARROWS_FLAT_END) &&
1064 (ArrowLayout(spin) != DtARROWS_SPLIT) &&
1065 (ArrowLayout(spin) != DtARROWS_BEGINNING) &&
1066 (ArrowLayout(spin) != DtARROWS_END)) {
1067 XtWarning(SB_ARROW_LAYOUT);
1068 ArrowLayout(spin) = DtARROWS_BEGINNING;
1070 if (RepeatDelay(spin) == 0) {
1071 XtWarning(SB_REPEAT_DELAY);
1072 RepeatDelay(spin) = 200;
1074 if (ItemCount(spin) < 0) {
1075 XtWarning(SB_ITEM_COUNT);
1076 ItemCount(spin) = 0;
1078 if ((ChildType(spin) == DtSTRING) &&
1079 ((Position(spin) < 0) ||
1080 ((Position(spin) >= ItemCount(spin)) &&
1081 (ItemCount(spin) > 0)))) {
1082 XtWarning(SB_POSITION_STRING);
1085 if ((DecimalPoints(spin) < 0) ||
1086 (DecimalPoints(spin) > MAX_FLOAT_DECIMALS)) {
1087 XtWarning(SB_DECIMAL_POINTS);
1088 DecimalPoints(spin) = 0;
1090 if (Minimum(spin) > Maximum(spin)) {
1091 XtWarning(SB_MIN_MAX);
1092 Minimum(spin) = Maximum(spin);
1094 if ((ChildType(spin) == DtNUMERIC) &&
1095 ((Position(spin) < Minimum(spin)) ||
1096 (Position(spin) > Maximum(spin)) ||
1097 ((Position(spin) % NumericIncrement(spin)) != 0))) {
1098 XtWarning(SB_POSITION_NUMERIC);
1099 Position(spin) = Minimum(spin);
1105 * Destroy procedure called by the toolkit.
1108 Destroy(DtSpinBoxWidget spin)
1112 if ((int)Timer(spin))
1114 XtRemoveTimeOut(Timer(spin));
1115 Timer(spin) = (XtIntervalId)NULL;
1118 if (ItemCount(spin)>0) {
1119 for (i = 0; i < ItemCount(spin); i++) {
1120 XmStringFree((Items(spin))[i]);
1122 XtFree((char*)(Items(spin)));
1126 * Don't remove callbacks and event handlers set on the children,
1127 * this has already been done by Xt (children are cleaned up before
1134 * Resize function called by toolkit. The size of our spin-box
1135 * has already been changed. That is why we must store
1136 * old_width and old_height.
1139 Resize(DtSpinBoxWidget spin)
1141 ClearShadow(spin, TRUE);
1142 LayoutChildren(spin);
1144 OldWidth(spin) = spin->core.width;
1145 OldHeight(spin) = spin->core.height;
1150 * Redisplay function called by toolkit. The widget didn't change size,
1151 * so just redisplay the shadow.
1154 Redisplay( DtSpinBoxWidget w,
1163 * GeometryManager function called by toolkit when a child resizes/moves.
1164 * We are not allowing any changes but width/height of the text-field.
1165 * this is because the user can retrieve the text-field and make changes
1166 * that we want to honor. If they mess around with the label or arrow,
1167 * then we won't honor the request.
1168 * If the text-field requests a change, then make the change, and allow
1169 * our SetSpinBoxSize() and LayoutChildren() figure out what size will
1171 * Returning GeometryDone was suppose to tell the toolkit
1172 * that we resized the child ourselves, but the text-field had trouble
1173 * with this (its' geometry_manager wasn't called or working right?), so
1174 * we return GeometryYes.
1176 static XtGeometryResult
1177 GeometryManager(Widget w, /* child */
1178 XtWidgetGeometry *request,
1179 XtWidgetGeometry *reply)
1182 DtSpinBoxWidget spin = (DtSpinBoxWidget)XtParent(w);
1183 /* Resolution Independent */
1185 Dimension width, height, border_width;
1187 unsigned char unit_type;
1189 /* Ignore everything but text-field */
1190 if (w != Text(spin) ) {
1191 return(XtGeometryNo);
1194 /* Only allow width/height changes */
1195 if (!(request->request_mode & (CWWidth | CWHeight)))
1196 return(XtGeometryNo);
1198 /* Resolution Independent */
1199 XtSetArg(args[0], XmNunitType, &unit_type);
1200 XtGetValues(w, args, 1);
1201 if ( unit_type != XmPIXELS) {
1202 XtSetArg(args[0], XmNunitType, XmPIXELS);
1203 XtSetValues(w, args, 1);
1206 /* Set the text-field to the requested size */
1207 if (request->request_mode & CWWidth) {
1209 XtSetArg(args[n], XmNwidth, &width); n++;
1211 if (request->request_mode & CWHeight) {
1213 XtSetArg(args[n], XmNheight, &height); n++;
1216 XtSetArg(args[n], XmNborderWidth, &border_width); n++;
1217 XtGetValues(w, args, n);
1218 XtResizeWidget(w, width, height, border_width);
1219 if ( unit_type != XmPIXELS) {
1220 XtSetArg(args[0], XmNunitType, unit_type);
1221 XtSetValues(w, args, 1);
1224 ClearShadow(spin, TRUE);
1225 if (RecomputeSize(spin))
1226 SetSpinBoxSize(spin);
1227 LayoutChildren(spin);
1229 return(XtGeometryDone);
1233 * This function sets the size of the spin_box widget based on the
1234 * current size of the children. Don't worry if it doesn't work, the
1235 * children will be squeezed in later.
1238 SetSpinBoxSize(DtSpinBoxWidget spin)
1240 Widget text_holder = Editable(spin) ? Text(spin) : Label(spin);
1241 Dimension shadow = SPIN_SHADOW(spin) * 2;
1242 Dimension arrow_width, arrow_height;
1243 /* MotifBc & Resolution Independent */
1244 Dimension height, width;
1246 unsigned char unit_type = MUnitType(spin);
1249 /* Resolution Independent */
1250 if (unit_type != XmPIXELS) {
1251 XtSetArg(args[0], XmNunitType, XmPIXELS);
1252 XtSetValues((Widget)spin, args, 1);
1253 XtSetValues(text_holder, args, 1);
1256 XtSetArg(args[0], XmNheight, &height);
1257 XtSetArg(args[1], XmNwidth, &width);
1258 XtGetValues(text_holder, args, 2);
1260 * Find out how big the arrow can be (needed to get
1261 * width for text_holder).
1263 arrow_width = (Dimension)((float)height * ARROW_MULT);
1264 arrow_width = (arrow_width < ARROW_MIN) ? ARROW_MIN : arrow_width;
1266 /* Get height based on arrow width */
1267 arrow_height = arrow_width;
1268 if ((ArrowLayout(spin) == DtARROWS_BEGINNING) ||
1269 (ArrowLayout(spin) == DtARROWS_END))
1270 arrow_height += arrow_height;
1272 /* Make height bigger of 2 - arrows vs text_holder */
1273 if (arrow_height > (Dimension)height)
1274 height = arrow_height;
1276 /* If not stacked add extra width for arrows */
1277 if ((ArrowLayout(spin) != DtARROWS_BEGINNING) &&
1278 (ArrowLayout(spin) != DtARROWS_END)) {
1279 arrow_width += arrow_width;
1282 (void)XtMakeResizeRequest((Widget)spin, arrow_width +
1284 (SPIN_MARGIN_W(spin) * 2),
1285 height + shadow + (SPIN_MARGIN_H(spin) * 2),
1287 OldWidth(spin) = Width(spin);
1288 OldHeight(spin) = Height(spin);
1290 /* Resolution Independent */
1291 if (unit_type != XmPIXELS) {
1292 XtSetArg(args[0], XmNunitType, unit_type);
1293 XtSetValues((Widget)spin, args, 1);
1294 XtSetValues(text_holder, args, 1);
1299 * This function makes the text_holder (label or text-field) smaller
1300 * if the spin_box couldn't grow to the needed full size. It will
1301 * also make the text_holder grow if there is space. The textfield will
1302 * grow with the spin_box, but the label will only grow to its'
1303 * maximum size. The label will also shrink down to nothing, but the
1304 * text-field will always keep its' core height.
1307 ForceChildSizes(DtSpinBoxWidget spin)
1309 Dimension available_height, available_width, arrow_width;
1310 /* MotifBc & Resolution Independent */
1311 Dimension width, height, border_width;
1313 unsigned char unit_type = XmPIXELS;
1315 /* Resolution Independent */
1316 if (MUnitType(spin) != XmPIXELS) {
1317 unit_type = MUnitType(spin);
1318 XtSetArg(args[0], XmNunitType, XmPIXELS);
1319 XtSetValues(UpArrow(spin), args, 1);
1320 XtSetValues(DownArrow(spin), args, 1);
1321 if (Editable(spin) == False)
1322 XtSetValues(Label(spin), args, 1);
1324 XtSetValues(Text(spin), args, 1);
1327 CalculateSizes(spin, &available_width, &available_height, &arrow_width);
1329 if (Editable(spin) == FALSE) { /** label **/
1330 if (available_width > LabelMaxLength(spin))
1331 available_width = LabelMaxLength(spin);
1333 if ((available_width != (Label(spin))->core.width) ||
1334 (available_height != (Label(spin))->core.height))
1335 XtResizeWidget(Label(spin), available_width, available_height,
1336 (Label(spin))->core.border_width);
1338 else if ((Text(spin))->core.width != available_width) /** TextField **/
1339 XtResizeWidget(Text(spin), available_width,
1340 (Text(spin))->core.height,
1341 (Text(spin))->core.border_width);
1342 if ((arrow_width != UpArrow(spin)->core.width) ||
1343 ((UpArrow(spin))->core.height != arrow_width)) {
1344 available_height = (available_height < ARROW_MIN) ? ARROW_MIN :
1346 XtResizeWidget(UpArrow(spin), arrow_width, arrow_width,
1347 (UpArrow(spin))->core.border_width);
1349 if ((arrow_width != (DownArrow(spin))->core.width) ||
1350 ((DownArrow(spin))->core.height != arrow_width)) {
1351 available_height = (available_height < ARROW_MIN) ? ARROW_MIN :
1353 XtResizeWidget(DownArrow(spin), arrow_width, arrow_width,
1354 DownArrow(spin)->core.border_width);
1356 /* Resolution Independent */
1357 if (MUnitType(spin) != XmPIXELS) {
1358 XtSetArg(args[0], XmNunitType, unit_type);
1359 XtSetValues(UpArrow(spin), args, 1);
1360 XtSetValues(DownArrow(spin), args, 1);
1361 if (Editable(spin) == False)
1362 XtSetValues(Label(spin), args, 1);
1364 XtSetValues(Text(spin), args, 1);
1369 CalculateSizes (DtSpinBoxWidget spin,
1372 Dimension *parrow_width)
1374 Dimension width, height, arrow_width;
1376 /* Calculate available height for children */
1377 if ((height = spin->core.height - (SPIN_SHADOW(spin) * 2) -
1378 (SPIN_MARGIN_H(spin) * 2)) <= 0)
1381 /* Get initial available width for children */
1382 width = (spin->core.width - (SPIN_SHADOW(spin) * 2) -
1383 (SPIN_MARGIN_W(spin) * 2));
1385 /* label only grows to maximum width needed */
1386 if ((Editable(spin) == FALSE) &&
1387 (height > LabelMaxHeight(spin)))
1388 height = LabelMaxHeight(spin);
1389 else if (Editable(spin))
1390 height = (Text(spin))->core.height;
1393 * Find out how big the arrow can be (needed to get
1394 * width for text_holder).
1396 arrow_width = (Dimension)(height * ARROW_MULT);
1397 arrow_width = (arrow_width < ARROW_MIN) ? ARROW_MIN : arrow_width;
1399 /* Make sure width isn't too small or too big */
1400 if ((width -= arrow_width) <= 0)
1403 /* If not stacked subtract extra arrow */
1404 if ((ArrowLayout(spin) != DtARROWS_BEGINNING) &&
1405 (ArrowLayout(spin) != DtARROWS_END)) {
1406 width -= arrow_width;
1409 if (pwidth) *pwidth = width;
1410 if (pheight) *pheight = height;
1411 if (parrow_width) *parrow_width = arrow_width;
1415 * This function positions the children within the spin_box widget.
1416 * It calls ForceChildSizes() to make sure the children fit within the
1417 * spin_box widget, but it will not try to resize the spin_box widget.
1420 LayoutChildren(DtSpinBoxWidget spin)
1422 Widget text_holder = Editable(spin) ? Text(spin) : Label(spin);
1423 Position start_x = SPIN_SHADOW(spin) + SPIN_MARGIN_W(spin);
1424 Position start_y = SPIN_SHADOW(spin) + SPIN_MARGIN_H(spin);
1425 Dimension available_height = spin->core.height - (start_y * 2);
1426 Position y, arrow_y;
1427 Dimension arrow_height;
1428 /* Resolution Independent */
1430 unsigned char unit_type = XmPIXELS;
1432 ForceChildSizes(spin);
1434 /* Resolution Independent */
1435 if (MUnitType(spin) != XmPIXELS) {
1436 unit_type = MUnitType(spin);
1437 XtSetArg(args[0], XmNunitType, XmPIXELS);
1438 XtSetValues(UpArrow(spin), args, 1);
1439 XtSetValues(DownArrow(spin), args, 1);
1440 XtSetValues(text_holder, args, 1);
1443 /* Center text_holder within spin_box */
1444 y = available_height - text_holder->core.height;
1445 y = ((y < 0) ? 0 : y)/2 + start_y;
1447 arrow_height = (UpArrow(spin))->core.height;
1448 if ((ArrowLayout(spin) == DtARROWS_BEGINNING) ||
1449 (ArrowLayout(spin) == DtARROWS_END))
1450 arrow_height += arrow_height;
1451 arrow_y = available_height - arrow_height;
1452 arrow_y = ((arrow_y < 0) ? 0 : arrow_y)/2 + start_y;
1454 switch (ArrowLayout(spin)) {
1455 case DtARROWS_FLAT_BEGINNING:
1456 XtMoveWidget(UpArrow(spin), start_x, arrow_y);
1457 start_x += (UpArrow(spin))->core.width;
1458 XtMoveWidget(DownArrow(spin), start_x, arrow_y);
1459 start_x += (DownArrow(spin))->core.width;
1460 XtMoveWidget(text_holder, start_x, y);
1462 case DtARROWS_FLAT_END:
1463 XtMoveWidget(text_holder, start_x, y);
1465 * This start_x places arrow right after text_holder. With
1466 * labels we want the arrow at the end of the spin_box, so
1467 * the user can use recompute_size more effectively.
1468 * start_x += text_holder->core.width;
1470 start_x = (spin->core.width - start_x -
1471 (UpArrow(spin))->core.width -
1472 (DownArrow(spin))->core.width);
1473 XtMoveWidget(UpArrow(spin), start_x, arrow_y);
1474 start_x += (UpArrow(spin))->core.width;
1475 XtMoveWidget(DownArrow(spin), start_x, arrow_y);
1477 case DtARROWS_SPLIT:
1478 XtMoveWidget(DownArrow(spin), start_x, arrow_y);
1479 start_x += (DownArrow(spin))->core.width;
1480 XtMoveWidget(text_holder, start_x, y);
1481 start_x += text_holder->core.width;
1482 XtMoveWidget(UpArrow(spin), start_x, arrow_y);
1484 case DtARROWS_BEGINNING:
1485 XtMoveWidget(UpArrow(spin), start_x, arrow_y);
1486 arrow_y += (UpArrow(spin))->core.height;
1487 XtMoveWidget(DownArrow(spin), start_x, arrow_y);
1488 start_x += (DownArrow(spin))->core.width;
1489 XtMoveWidget(text_holder, start_x, y);
1492 XtMoveWidget(text_holder, start_x, y);
1494 * This start_x places arrow right after text_holder. With
1495 * labels we want the arrow at the end of the spin_box, so
1496 * the user can use recompute_size more effectively.
1497 * start_x += text_holder->core.width;
1499 start_x = spin->core.width - start_x - (UpArrow(spin))->core.width;
1500 XtMoveWidget(UpArrow(spin), start_x, arrow_y);
1501 arrow_y += (UpArrow(spin))->core.width;
1502 XtMoveWidget(DownArrow(spin), start_x, arrow_y);
1505 /* Resolution Independent */
1506 if (MUnitType(spin) != XmPIXELS) {
1507 XtSetArg(args[0], XmNunitType, unit_type);
1508 XtSetValues(UpArrow(spin), args, 1);
1509 XtSetValues(DownArrow(spin), args, 1);
1510 XtSetValues(text_holder, args, 1);
1516 * SetValues() routine for SpinBox widget. Most of the real work
1517 * is done in SetItems() and SetNumeric(). If items is set we store
1518 * our own XmStrings.
1519 * This function was built with static spin_boxs in mind, meaning that
1520 * is-numeric or editable resources won't be changed constantly. These
1521 * resources can be changed, but this function doesn't handle them in
1522 * a super-efficient manor. for example, changing child-type will cause
1523 * the label to be resize even if it isn't managed.
1526 SetValues( DtSpinBoxWidget current,
1527 DtSpinBoxWidget request,
1528 DtSpinBoxWidget new)
1530 DtSpinBoxPart *new_p = (DtSpinBoxPart*)
1531 &(XmField(new,ipot,DtSpinBox,label,Widget));
1532 DtSpinBoxPart *cur_p = (DtSpinBoxPart*)
1533 &(XmField(current,ipot,DtSpinBox,label,Widget));
1536 Boolean label_size_changed = FALSE;
1539 /* Resolution Independent */
1540 unsigned char unit_type = MUnitType(new);
1542 CheckResources(new);
1544 if (Text(new) != Text(current)) {
1546 Text(new) = Text(current);
1550 * Editable resource changed. If the widget (textField or Label)
1551 * doesn't exist, then create it.
1553 if (Editable(new) != Editable(current)) {
1554 if (Editable(new)) {
1555 XtUnmanageChild(Label(new));
1556 if (Text(new) == NULL) {
1557 widget_name = XtMalloc(strlen(XtName((Widget)new)) + 10);
1558 sprintf(widget_name, "%s_TF", XtName((Widget)new));
1560 XtSetArg(args[n], XmNcolumns, TextColumns(new)); n++;
1561 XtSetArg(args[n], XmNmaxLength, TextMaxLength(new)); n++;
1562 XtSetArg(args[n], XmNmarginWidth, 2); n++;
1563 XtSetArg(args[n], XmNmarginHeight, 2); n++;
1564 if (unit_type != XmPIXELS) {
1565 XtSetArg(args[n], XmNunitType, XmPIXELS); n++;
1567 Text(new) = XtCreateManagedWidget(widget_name,
1568 xmTextFieldWidgetClass,
1569 (Widget)new, args, n);
1570 XtAddCallback(Text(new), XmNlosingFocusCallback,
1571 text_losing_focus_cb, (XtPointer)new);
1572 XtAddCallback(Text(new), XmNactivateCallback,
1573 text_activate_cb, (XtPointer)new);
1574 XtAddCallback(Text(new), XmNfocusCallback,
1575 text_focus_cb, (XtPointer)new);
1576 XtFree(widget_name);
1577 if (unit_type != XmPIXELS) {
1578 XtSetArg(args[n], XmNunitType, unit_type); n++;
1579 XtSetValues(Text(new), args, 1);
1583 XtManageChild(Text(new));
1586 XtUnmanageChild(Text(new));
1587 if (Label(new) == NULL) {
1588 widget_name = XtMalloc(strlen(XtName((Widget)new)) + 10);
1589 sprintf(widget_name, "%s_Label", XtName((Widget)new));
1591 XtSetArg(args[n], XmNalignment, Alignment(new)); n++;
1592 XtSetArg(args[n], XmNrecomputeSize, FALSE); n++;
1593 XtSetArg(args[n], XmNlabelString, InitLabel); n++;
1594 XtSetArg(args[n], XmNmarginLeft, LABEL_PADDING); n++;
1595 XtSetArg(args[n], XmNmarginRight, LABEL_PADDING); n++;
1596 XtSetArg(args[n], XmNmarginWidth, TEXT_CONTEXT_MARGIN); n++;
1597 XtSetArg(args[n], XmNmarginHeight, 0); n++;
1598 if (unit_type != XmPIXELS) {
1599 XtSetArg(args[n], XmNunitType, XmPIXELS); n++;
1601 Label(new) = XtCreateManagedWidget(widget_name,
1603 (Widget)new, args, n);
1604 XtOverrideTranslations((Widget)Label(new), child_trans);
1605 XtFree(widget_name);
1606 if (unit_type != XmPIXELS) {
1607 XtSetArg(args[n], XmNunitType, unit_type); n++;
1608 XtSetValues(Label(new), args, 1);
1612 XtManageChild(Label(new));
1615 * Text-fields and labels have different shadows. Only
1616 * change if user didn't change the shadow resource.
1618 if (SPIN_SHADOW(new) == SPIN_SHADOW(current))
1619 SPIN_SHADOW(new) = (Editable(new)) ? TEXT_FIELD_SHADOW :
1623 /* Check arrow sensitivity (up arrow is right arrow)*/
1624 if (ArrowSensitivity(new) != ArrowSensitivity(current)) {
1625 XtSetSensitive(UpArrow(new),
1626 ((ArrowSensitivity(new) == DtARROWS_SENSITIVE) ||
1627 (ArrowSensitivity(new) == DtARROWS_INCREMENT_SENSITIVE)));
1628 XtSetSensitive(DownArrow(new),
1629 ((ArrowSensitivity(new) == DtARROWS_SENSITIVE) ||
1630 (ArrowSensitivity(new) == DtARROWS_DECREMENT_SENSITIVE)));
1634 * Check arrow layout. Only need to change arrows if going to or
1635 * from DtARROWS_SPLIT. The LayoutChildren() routine actually
1636 * positions the arrows in the correct place.
1638 if (ArrowLayout(new) != ArrowLayout(current)) {
1639 if (ArrowLayout(new) == DtARROWS_SPLIT) {
1640 XtSetArg(args[0], XmNarrowDirection, XmARROW_RIGHT);
1641 XtSetValues(UpArrow(new), args, 1);
1642 XtSetArg(args[0], XmNarrowDirection, XmARROW_LEFT);
1643 XtSetValues(DownArrow(new), args, 1);
1646 XtSetArg(args[0], XmNarrowDirection, XmARROW_UP);
1647 XtSetValues(UpArrow(new), args, 1);
1648 XtSetArg(args[0], XmNarrowDirection, XmARROW_DOWN);
1649 XtSetValues(DownArrow(new), args, 1);
1653 if (Text(new) && (Text(new) == Text(current))) {
1655 if (TextColumns(new) != TextColumns(current)) {
1656 XtSetArg(args[n], XmNcolumns, TextColumns(new)); n++;
1658 if (TextMaxLength(new) != TextMaxLength(current)) {
1659 XtSetArg(args[n], XmNmaxLength, TextMaxLength(new)); n++;
1662 XtSetValues(Text(new), args, n);
1666 * LabelWidget alignment has changed.
1668 if (Label(new) && (Alignment(new) != Alignment(current))) {
1669 XtSetArg(args[0], XmNalignment, Alignment(new));
1670 XtSetValues(Label(new), args, 1);
1673 store_info = ((Items(new) != Items(current)) ||
1674 (ItemCount(new) != ItemCount(current)) ||
1675 (DecimalPoints(new) != DecimalPoints(current)) ||
1676 (Maximum(new) != Maximum(current)) ||
1677 (Minimum(new) != Minimum(current)) ||
1678 (NumericIncrement(new) != NumericIncrement(current)) ||
1679 ((ChildType(new) == DtNUMERIC) &&
1680 (Position(new) != Position(current))));
1682 StoreResourceInfo(new_p, cur_p, (Items(new) != Items(current)));
1684 if (Label(new) && (store_info ||
1685 (Label(new) != Label(current)) ||
1686 (ChildType(new) != ChildType(current)))) {
1687 SetMaximumLabelSize(new_p);
1688 label_size_changed = TRUE;
1692 (Alignment(new) != Alignment(current)) ||
1693 (Editable(new) != Editable(current)) ||
1694 (Position(new) != Position(current)) ||
1695 (Label(new) != Label(current)) ||
1696 (ChildType(new) != ChildType(current))) {
1698 SetTextFieldData(new);
1704 * Must recalculate the spin_box and re-layout the children.
1705 * If this is not editable, then set the label to its' maximum
1706 * size; it will get chopped if it is too big. This is needed
1707 * because we shrink the label down, and SetSpinBoxSize() uses
1708 * the label's core sizes to figure what size to become.
1710 if ((Editable(new) != Editable(current)) ||
1711 (SPIN_MARGIN_W(new) != SPIN_MARGIN_W(current)) ||
1712 (SPIN_MARGIN_H(new) != SPIN_MARGIN_H(current)) ||
1713 (SPIN_SHADOW(new) != SPIN_SHADOW(current)) ||
1714 (ArrowLayout(new) != ArrowLayout(current)) ||
1715 (!(Editable(new)) && label_size_changed)) {
1716 ClearShadow(current, TRUE);
1717 if (RecomputeSize(new))
1718 SetSpinBoxSize(new);
1719 LayoutChildren(new);
1723 if(CBgPixel(new) != CBgPixel(current))
1725 XtSetArg(args[n],XmNbackground,CBgPixel(new));n++;
1727 if(CBgPixmap(new) != CBgPixmap(current))
1729 XtSetArg(args[n],XmNbackgroundPixmap,CBgPixmap(new));n++;
1731 if(MFgPixel(new) != MFgPixel(current))
1733 XtSetArg(args[n],XmNforeground,MFgPixel(new));n++;
1736 XtSetValues (Text(new),args,n);
1738 XtSetValues (Label(new),args,n);
1740 XtSetValues (UpArrow(new),args,n);
1742 XtSetValues (DownArrow(new),args,n);
1749 * This function clears the shadow around our widget. If all is TRUE,
1750 * then clear all 4 sides; otherwise, only clear the right and bottom
1751 * sides (during resize).
1754 ClearShadow( DtSpinBoxWidget w,
1757 Dimension shadow = SPIN_SHADOW(w);
1758 Dimension margin_w = SPIN_MARGIN_W(w);
1759 Dimension margin_h = SPIN_MARGIN_H(w);
1761 if ((shadow > 0) && XtIsRealized((Widget)w)) {
1763 XClearArea(XtDisplayOfObject((Widget)w),
1764 XtWindowOfObject((Widget)w),
1766 OldWidth(w) - (margin_w * 2),
1768 XClearArea(XtDisplayOfObject((Widget)w),
1769 XtWindowOfObject((Widget)w),
1770 margin_w, margin_h, shadow,
1771 OldHeight(w) - (margin_h * 2), FALSE);
1773 XClearArea(XtDisplayOfObject((Widget)w), XtWindowOfObject((Widget)w),
1774 margin_w, OldHeight(w) - margin_h - shadow,
1775 OldWidth(w) - (margin_w * 2), shadow, FALSE);
1776 XClearArea(XtDisplayOfObject((Widget)w), XtWindowOfObject((Widget)w),
1777 OldWidth(w) - margin_w - shadow,
1779 OldHeight(w) - (margin_h * 2), FALSE);
1781 DrawHighlight(w, TRUE);
1785 * This functions draws the shadow around our spin_box.
1788 DrawShadow(DtSpinBoxWidget w)
1790 Dimension shadow = SPIN_SHADOW(w);
1791 Dimension margin_w = SPIN_MARGIN_W(w);
1792 Dimension margin_h = SPIN_MARGIN_H(w);
1794 if ((shadow > 0) && XtIsRealized((Widget)w)) {
1795 XmeDrawShadows(XtDisplayOfObject((Widget)w),
1796 XtWindowOfObject((Widget)w),
1797 w->manager.top_shadow_GC,
1798 w->manager.bottom_shadow_GC,
1800 w->core.width - (margin_w * 2),
1801 w->core.height - (margin_h * 2),
1802 shadow, XmSHADOW_OUT);
1804 DrawHighlight(w, FALSE);
1808 * This function sets up the items information for the SpinBox, as
1809 * well as variables needed for child_type.
1812 StoreResourceInfo( DtSpinBoxPart *spin_p,
1813 DtSpinBoxPart *old_p,
1816 XmStringTable table;
1817 XmFontList font_list;
1818 Dimension width, height;
1819 Dimension longest = 0;
1820 Dimension highest = 0;
1823 if (do_items && spin_p->items) {
1824 /* Free up current items if needed */
1825 if (old_p && old_p->items) {
1826 for (i = 0; i < old_p->item_count; i++) {
1827 XmStringFree(old_p->items[i]);
1829 XtFree((char*)old_p->items);
1833 * Loop through all the items, copy them into our space.
1835 table = (XmStringTable)XtMalloc(sizeof(XmString) * spin_p->item_count);
1836 for (i = 0; i < spin_p->item_count; i++) {
1837 table[i] = XmStringCopy(spin_p->items[i]);
1839 spin_p->items = table;
1840 for (i = 0; i < spin_p->item_count; i++)
1841 spin_p->items[i] = table[i];
1845 * Store the numeric information
1848 /* get base number for convert ints to floats */
1849 for (i = 0; i < spin_p->decimal_points; i++)
1852 /* Set new initial values */
1853 spin_p->min = (float)spin_p->minimum/base;
1854 spin_p->max = (float)spin_p->maximum/base;
1855 spin_p->increment = (float)spin_p->numeric_increment/base;
1857 spin_p->current = (float)spin_p->position/base;
1859 /* Create format string used to build correct XmString value */
1860 spin_p->float_format[0] = '%';
1861 sprintf((char*)(spin_p->float_format+1), ".%df", spin_p->decimal_points);
1865 /* Caller must free string */
1867 GetTextString(XmString xm_string)
1869 XmStringContext context;
1870 XmStringComponentType type;
1871 XmStringCharSet charset;
1872 XmStringDirection direction;
1873 XmStringComponentType unknown_tag;
1877 Boolean done = FALSE;
1879 XmStringInitContext(&context, xm_string);
1881 /* Loop until 1st char* found */
1883 type = XmStringGetNextComponent(context, &text, &charset,
1884 &direction, &unknown_tag,
1887 case XmSTRING_COMPONENT_END:
1890 case XmSTRING_COMPONENT_TEXT:
1891 case XmSTRING_COMPONENT_LOCALE_TEXT:
1898 XmStringFreeContext(context);
1903 * Take the string out of the list and put it into the text-field.
1904 * text-fields don't handle xm-strings, so we must get the char*
1905 * out of it (only getting the first segment). This is slower than
1906 * storing the text-strings (char*) ourselves, but that would take
1907 * up a lot of memory. Since this setting happens during a user
1908 * action, speed isn't a problem.
1911 SetTextFieldData(DtSpinBoxWidget spin)
1913 char string[NUMERIC_LENGTH];
1919 if (ChildType(spin) == DtNUMERIC) {
1920 sprintf(string, FloatFormat(spin), (float)(Current(spin)));
1921 XtSetArg(arg, XmNvalue, string);
1922 XtSetValues(Text(spin), &arg, 1);
1925 if (ItemCount(spin) == 0){
1926 XtSetArg(arg, XmNvalue, "");
1927 XtSetValues(Text(spin), &arg, 1);
1931 xm_string = (Items(spin))[Position(spin)];
1932 if (text = GetTextString(xm_string)) {
1933 XtSetArg(arg, XmNvalue, text);
1934 XtSetValues(Text(spin), &arg, 1);
1942 * Set the maximum size of the label, depending on the
1943 * characteristics of the list of items. Not very efficient
1944 * if switching from numeric to non-numeric.
1947 SetMaximumLabelSize(DtSpinBoxPart *spin_p)
1950 XmFontList font_list;
1951 char string[NUMERIC_LENGTH];
1952 Dimension width, height;
1953 Dimension longest = 0;
1954 Dimension highest = 0;
1957 /* Resolution Independent */
1958 unsigned char unit_type;
1960 /* Get font info from the widget */
1961 XtSetArg(args[0], XmNfontList, &font_list);
1962 XtSetArg(args[1], XmNunitType, &unit_type); /* resolution Independent */
1963 XtGetValues(spin_p->label, args, 2);
1964 if ( unit_type != XmPIXELS) {
1965 XtSetArg(args[0], XmNunitType, XmPIXELS);
1966 XtSetValues(spin_p->label, args, 1);
1969 if (spin_p->child_type == DtNUMERIC) {
1970 /* Find out maximum size of the widget from min/max */
1971 sprintf(string, spin_p->float_format, spin_p->min);
1972 xm_string = XmStringCreateLocalized(string);
1973 XmStringExtent(font_list, xm_string, &longest, &highest);
1974 XmStringFree(xm_string);
1975 sprintf(string, spin_p->float_format, spin_p->max);
1976 xm_string = XmStringCreateLocalized(string);
1977 XmStringExtent(font_list, xm_string, &width, &height);
1978 XmStringFree(xm_string);
1980 longest = (width > longest) ? width : longest;
1981 highest = (height > highest) ? height : highest;
1983 else if (spin_p->items) {
1985 * Loop through all the items to find the biggest dimensions
1987 for (i = 0; i < spin_p->item_count; i++) {
1988 XmStringExtent(font_list, spin_p->items[i], &width, &height);
1989 longest = (width > longest) ? width : longest;
1990 highest = (height > highest) ? height : highest;
1994 XmStringExtent(font_list, InitLabel, &longest, &highest);
1997 spin_p->label_max_length =
1998 ( (Dimension)(longest + ( (LABEL_PADDING + TEXT_CONTEXT_MARGIN) *2) ) >
1999 (Dimension)Width(spin_p->label) ) ?
2000 (longest + ((LABEL_PADDING+TEXT_CONTEXT_MARGIN) * 2)) :
2001 Width(spin_p->label);
2003 spin_p->label_max_height = highest > Height(spin_p->label) ?
2004 highest : Height(spin_p->label);
2005 XtResizeWidget(spin_p->label, spin_p->label_max_length,
2006 spin_p->label_max_height,
2007 spin_p->label->core.border_width);
2009 /* Resolution Independent */
2010 if ( unit_type != XmPIXELS) {
2011 XtSetArg(args[0], XmNunitType, unit_type);
2012 XtSetValues(spin_p->label, args, 1);
2018 * Put the current list item into the label.
2021 SetLabelData(DtSpinBoxWidget spin)
2024 char string[NUMERIC_LENGTH];
2025 int index = Position(spin);
2028 if (ChildType(spin) == DtNUMERIC) {
2029 sprintf(string, FloatFormat(spin), (float)Current(spin));
2030 xm_string = XmStringCreateLocalized(string);
2031 XtSetArg(arg, XmNlabelString, xm_string);
2032 XtSetValues(Label(spin), &arg, 1);
2036 * If the item is not empty, get the current item from the list, else
2039 xm_string = (ItemCount(spin)>0) ? (Items(spin))[index] : InitLabel;
2040 XtSetArg(arg, XmNlabelString, xm_string);
2041 XtSetValues(Label(spin), &arg, 1);
2046 * Timout dispatch routine. This calls the appropriate callback function
2047 * to simulate up or down arrow activation.
2050 timer_dispatch( XtPointer client_data,
2053 DtSpinBoxWidget spin_w = (DtSpinBoxWidget)client_data;
2055 Timer(spin_w) = (XtIntervalId)NULL;
2056 InitCb(spin_w) = FALSE;
2057 if (WhichArrow(spin_w) == XmARROW_UP) {
2058 if (Grabbed(spin_w)) {
2059 XtRemoveGrab(UpArrow(spin_w));
2060 Grabbed(spin_w) = FALSE;
2062 up_cb(NULL, client_data, NULL);
2065 if (Grabbed(spin_w)) {
2066 XtRemoveGrab(DownArrow(spin_w));
2067 Grabbed(spin_w) = FALSE;
2069 down_cb(NULL, client_data, NULL);
2074 TextFieldActivate(DtSpinBoxPart *spin_p)
2076 XmTextFieldWidget w = (XmTextFieldWidget)(spin_p->text);
2077 XmAnyCallbackStruct cb;
2078 char string[NUMERIC_LENGTH];
2082 Boolean free_me = TRUE;
2084 XtSetArg(arg, XmNvalue, &data);
2085 XtGetValues((Widget)w, &arg, 1);
2087 if (spin_p->child_type == DtNUMERIC) {
2088 sprintf(string, spin_p->float_format, (float)spin_p->current);
2092 else if (spin_p->items)
2093 text = GetTextString(spin_p->items[spin_p->position]);
2095 if (text && data && (strcmp(text, data) == 0)) {
2100 /* Only send callback if both are not NULL */
2101 else if (!((text == NULL) && (data == NULL))) {
2102 cb.reason = XmCR_ACTIVATE;
2105 if (XtHasCallbacks((Widget)w, XmNactivateCallback)==XtCallbackHasSome)
2106 XtCallCallbacks((Widget)w, XmNactivateCallback,
2108 if (text && free_me)
2114 * This function calls the appropriate callback for the spin_box.
2115 * It gathers the correct arguments and fills in the callback structure.
2118 SendCallback( DtSpinBoxWidget spin,
2120 Boolean value_changed,
2122 float current, /* Used for numeric */
2125 DtSpinBoxCallbackStruct cb;
2126 XmString xm_string = NULL;
2127 char string[NUMERIC_LENGTH];
2129 if (ChildType(spin) == DtNUMERIC) {
2130 sprintf(string, FloatFormat(spin), (float)current);
2131 xm_string = XmStringCreateLocalized(string);
2134 xm_string = (ItemCount(spin)>0) ? (Items(spin))[position] : InitLabel;
2135 xm_string = XmStringCopy(xm_string);
2139 cb.reason = DtCR_OK;
2140 else if (WhichArrow(spin) == XmARROW_UP)
2141 cb.reason = DtCR_SPIN_NEXT;
2143 cb.reason = DtCR_SPIN_PRIOR;
2146 cb.widget = (Widget)spin;
2147 cb.position = position;
2148 cb.value = xm_string;
2149 cb.crossed_boundary = crossed;
2150 if (value_changed) {
2151 XtCallCallbackList((Widget)spin, ValueChangedCallback(spin),
2156 XtCallCallbackList((Widget)spin, ModifyVerifyCallback(spin),
2159 XmStringFree(xm_string);
2166 * This function gets called by the up/down arm callback functions.
2167 * We set up the timer and send the modify-verify and value-changed
2169 * There are potential problems if the user does some weird stuff
2170 * in the callbacks. I have added protection against the case where
2171 * a user does a grab (with XtAddGrab/XtPopup/etc.) in the callbacks.
2172 * Grabbing in the callback would cause us to lose the button-release
2173 * (disarm), which would make the timer go on forever. A grab is
2174 * done after the callbacks just to make sure we will receive the
2175 * button-release. The button-release will call disarm_cb() which will
2176 * un-grab and disable the timer. I have also added a leave callback
2177 * which helps to protect against these kinds of problems.
2178 * If the callback goes into another event-loop (which I hope would
2179 * never happen), we would spin continuously (since our XtAddGrab never
2180 * get called), until the user left the window (which would call
2181 * grab_leave_cb). The grabbed flag gets set if we do the grab, so that
2182 * we know if we can remove the grab. Our XtAddGrab() might not get called
2183 * if the callback enters another event-loop.
2185 * The event sent in the callback will be NULL during continuous spinning.
2188 FinishUpDown( DtSpinBoxWidget spin,
2189 XtPointer arrow_call_data,
2194 XmArrowButtonCallbackStruct *arrow_data;
2195 XEvent *last_event = NULL;
2196 int repeat_delay = RepeatDelay(spin);
2199 repeat_delay = InitialDelay(spin);
2200 Timer(spin) = XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)spin),
2201 repeat_delay, timer_dispatch, (XtPointer)spin);
2203 /* Try to get Xevent */
2204 if (arrow_data = (XmArrowButtonCallbackStruct*)arrow_call_data)
2205 last_event = arrow_data->event;
2208 * Send modify_verify callback. If user says no, then
2209 * clear the timer and reset the state before returning.
2211 if (SendCallback(spin, last_event, FALSE, new_position,
2212 new_current, crossed) == FALSE) {
2213 XtRemoveTimeOut(Timer(spin));
2214 Timer(spin) = (XtIntervalId)NULL;
2215 InitCb(spin) = TRUE;
2219 /* User said yes, so set widget values */
2220 Position(spin) = new_position;
2221 Current(spin) = new_current;
2223 SetTextFieldData(spin);
2227 /* send value_changed callback */
2228 (void)SendCallback(spin, last_event, TRUE, Position(spin),
2229 Current(spin), crossed);
2231 /* See notes at top of function on XtAddGrab usage */
2232 Grabbed(spin) = TRUE;
2233 if (WhichArrow(spin) == XmARROW_UP)
2234 XtAddGrab(UpArrow(spin), FALSE, FALSE);
2236 XtAddGrab(DownArrow(spin), FALSE, FALSE);
2240 * Show the next value in the SpinBox. If numeric, just add the
2241 * increment value. If using string-table, get the next one in the
2242 * table. This function takes care of wrap around. Set the arrow
2243 * type. This is needed for the timer_dispatch function. up_cb
2244 * gets called the first time the button is pressed, and each time the
2246 * All widget internals are expected to be correct here; they
2247 * get verified when set by the user.
2251 XtPointer client_data,
2252 XtPointer call_data)
2254 DtSpinBoxWidget spin = (DtSpinBoxWidget)client_data;
2255 DtSpinBoxPart *spin_p = (DtSpinBoxPart*)
2256 &(XmField(spin,ipot,DtSpinBox,label,Widget));
2257 Boolean crossed_boundary = FALSE;
2258 int new_position = Position(spin);
2259 float new_current = Current(spin);
2262 if ( !_XmFocusIsHere( (Widget)spin) )
2263 XmProcessTraversal((Widget)spin,
2264 (XmTraversalDirection) XmTRAVERSE_CURRENT);
2267 TextFieldActivate(spin_p);
2270 * If non-numeric and no items then ignore the user activate event.
2272 if ((ChildType(spin) == DtSTRING) && (ItemCount(spin) == 0))
2275 if (ChildType(spin) == DtNUMERIC) {
2276 if ((new_current + Increment(spin)) > Max(spin)) {
2278 new_position = Minimum(spin);
2279 new_current = Min(spin);
2280 crossed_boundary = TRUE;
2283 XBell(XtDisplayOfObject((Widget)spin), 0);
2286 new_position += NumericIncrement(spin);
2287 new_current += Increment(spin);
2290 else if (ItemCount(spin) >0) {
2291 if (new_position == (ItemCount(spin) - 1)) {
2294 crossed_boundary = TRUE;
2297 XBell(XtDisplayOfObject((Widget)spin), 0);
2303 WhichArrow(spin) = XmARROW_UP;
2304 FinishUpDown(spin, call_data, new_position, new_current, crossed_boundary);
2309 * Show the previous value in the SpinBox. If numeric, just decrement
2310 * the increment value. If using string-table, get the previous one in the
2311 * table. This function takes care of wrap around. Set the arrow
2312 * type. This is needed for the timer_dispatch function. down_cb
2313 * gets called the first time the button is pressed, and each time the
2315 * All widget internals are expected to be correct here; they
2316 * get verified when set by the user.
2320 XtPointer client_data,
2321 XtPointer call_data)
2323 DtSpinBoxWidget spin = (DtSpinBoxWidget)client_data;
2324 DtSpinBoxPart *spin_p = (DtSpinBoxPart*)
2325 &(XmField(spin,ipot,DtSpinBox,label,Widget));
2326 XmArrowButtonCallbackStruct *arrow_data;
2327 XEvent *last_event = NULL;
2328 int repeat_delay = RepeatDelay(spin);
2329 Boolean crossed_boundary = FALSE;
2330 int new_position = Position(spin);
2331 float new_current = Current(spin);
2333 /* #5: Getting Focus */
2334 if ( !_XmFocusIsHere( (Widget)spin) )
2335 XmProcessTraversal((Widget)spin,
2336 (XmTraversalDirection) XmTRAVERSE_CURRENT);
2339 TextFieldActivate(spin_p);
2342 * If non-numeric and no items then ignore the user activate event.
2344 if ((ChildType(spin) == DtSTRING) && (ItemCount(spin) == 0))
2347 if (ChildType(spin) == DtNUMERIC) {
2348 if ((new_current - Increment(spin)) < Min(spin)) {
2350 new_current = Max(spin);
2351 new_position = Maximum(spin);
2352 crossed_boundary = TRUE;
2355 XBell(XtDisplayOfObject((Widget)spin), 0);
2358 new_current -= Increment(spin);
2359 new_position -= NumericIncrement(spin);
2362 else if (ItemCount(spin)>0) {
2363 if (new_position == 0) {
2365 new_position = ItemCount(spin) - 1;
2366 crossed_boundary = TRUE;
2369 XBell(XtDisplayOfObject((Widget)spin), 0);
2375 WhichArrow(spin) = XmARROW_DOWN;
2376 FinishUpDown(spin, call_data, new_position, new_current, crossed_boundary);
2380 disarm_cb( Widget w,
2381 XtPointer client_data,
2382 XtPointer call_data)
2384 DtSpinBoxWidget spin = (DtSpinBoxWidget)client_data;
2386 if ((int)Timer(spin)) {
2387 InitCb(spin) = TRUE;
2388 XtRemoveTimeOut(Timer(spin));
2389 Timer(spin) = (XtIntervalId)NULL;
2390 if (Grabbed(spin)) {
2392 Grabbed(spin) = FALSE;
2398 grab_leave_cb( Widget w,
2399 XtPointer client_data,
2403 DtSpinBoxWidget spin = (DtSpinBoxWidget)client_data;
2405 if ((int)Timer(spin) &&
2406 ((event->xcrossing.mode == NotifyGrab) ||
2407 (event->xcrossing.mode == NotifyUngrab) ||
2408 (!(event->xcrossing.state & Button1Mask)))) {
2409 InitCb(spin) = TRUE;
2410 XtRemoveTimeOut(Timer(spin));
2411 Timer(spin) = (XtIntervalId)NULL;
2412 if (Grabbed(spin)) {
2414 Grabbed(spin) = FALSE;
2420 * We get the text-field losing-focus callback, so pass it on to
2421 * the user if they requested it. Our losing-focus callback
2422 * is just a convenience callback, so that the user doesn't
2423 * have to get the text-field first. This make our integration
2424 * with XDesigner a little easier.
2427 text_losing_focus_cb( Widget w,
2428 XtPointer client_data,
2429 XtPointer call_data)
2431 DtSpinBoxWidget spin = (DtSpinBoxWidget)client_data;
2433 if (LosingFocusCallback(spin))
2434 XtCallCallbackList((Widget)spin,
2435 LosingFocusCallback(spin),
2436 (XtPointer)call_data);
2440 * We get the text-field activate callback, so pass it on to
2441 * the user if they requested it. Our activate callback
2442 * is just a convenience callback, so that the user doesn't
2443 * have to get the text-field first. This make our integration
2444 * with XDesigner a little easier.
2447 text_activate_cb(Widget w,
2448 XtPointer client_data,
2449 XtPointer call_data)
2451 DtSpinBoxWidget spin = (DtSpinBoxWidget)client_data;
2453 if (ActivateCallback(spin))
2454 XtCallCallbackList((Widget)spin,
2455 ActivateCallback(spin),
2456 (XtPointer)call_data);
2460 * We get the text-field focus callback, so pass it on to
2461 * the user if they requested it. Our focus callback
2462 * is just a convenience callback, so that the user doesn't
2463 * have to get the text-field first. This make our integration
2464 * with XDesigner a little easier.
2467 text_focus_cb( Widget w,
2468 XtPointer client_data,
2469 XtPointer call_data)
2471 DtSpinBoxWidget spin = (DtSpinBoxWidget)client_data;
2473 if (FocusCallback(spin))
2474 XtCallCallbackList((Widget)spin,
2475 FocusCallback(spin),
2476 (XtPointer)call_data);
2481 * Synthetic resource get functions.
2484 static XmImportOperator
2485 _XmSetSyntheticResForChild( Widget widget,
2489 return(XmSYNTHETIC_LOAD);
2493 _DtSpinBoxGetArrowSize( Widget w,
2494 int resource_offset,
2497 DtSpinBoxWidget spin = (DtSpinBoxWidget)w;
2502 XtSetArg(arg, XmNheight, &data);
2503 XtGetValues(UpArrow(spin), &arg, 1);
2504 *value = (XtArgVal)data;
2508 * Routines which manipulate the SpinBox list. These are external
2509 * for use by users of our widget.
2513 DtCreateSpinBox( Widget parent,
2518 return(XtCreateWidget(name, dtSpinBoxWidgetClass, parent,
2519 arglist, num_args));
2523 DtSpinBoxAddItem( Widget spinw,
2527 DtSpinBoxWidget spin = (DtSpinBoxWidget)spinw;
2528 DtSpinBoxPart *spin_p;
2529 XmString old, new_str, tmp;
2531 _DtWidgetToAppContext(spinw);
2534 spin_p = (DtSpinBoxPart*) &(XmField(spin,ipot,DtSpinBox,label,Widget));
2536 total_items = ItemCount(spin) + 1;
2537 Items(spin) = (XmString *)XtRealloc((char*)Items(spin),
2538 (sizeof(XmString) * total_items));
2539 new_str = XmStringCopy(item);
2541 pos--; /* User gives pos starting at 1 (0 means end of list) */
2543 if ((pos < 0) || (pos > ItemCount(spin)))
2544 pos = ItemCount(spin);
2546 if (pos >= ItemCount(spin))
2547 (Items(spin))[pos] = new_str;
2549 old = (Items(spin))[pos];
2550 (Items(spin))[pos] = new_str;
2551 for (pos++; pos < total_items; pos++) {
2552 tmp = (Items(spin))[pos];
2553 (Items(spin))[pos] = old;
2557 ItemCount(spin) = total_items;
2560 SetMaximumLabelSize(spin_p);
2561 if (Editable(spin) == FALSE) {
2562 ClearShadow(spin, TRUE);
2563 if (RecomputeSize(spin))
2564 SetSpinBoxSize(spin);
2565 LayoutChildren(spin);
2570 /* Update the text-field or label */
2572 SetTextFieldData(spin);
2582 DtSpinBoxDeletePos( Widget spinw,
2585 DtSpinBoxWidget spin = (DtSpinBoxWidget)spinw;
2586 DtSpinBoxPart *spin_p;
2588 _DtWidgetToAppContext(spinw);
2591 if (ItemCount(spin) < 1)
2597 spin_p = (DtSpinBoxPart*) &(XmField(spin,ipot,DtSpinBox,label,Widget));
2600 if ((pos < 0) || (pos > ItemCount(spin)))
2601 pos = ItemCount(spin) - 1;
2603 total_items = ItemCount(spin) - 1;
2604 XmStringFree((Items(spin))[pos]);
2606 /* To keep Position of SpinBox up to date */
2607 if (Position(spin) > 0 &&
2608 (Position(spin) >= total_items) || pos < Position(spin) )
2609 Position(spin) = Position(spin) - 1;
2611 if (pos < ItemCount(spin)) {
2612 for (; pos < total_items; pos++)
2613 (Items(spin))[pos] = (Items(spin))[pos+1];
2615 if (total_items > 0)
2616 Items(spin) = (XmString *)XtRealloc((char*)Items(spin),
2617 (sizeof(XmString) * total_items));
2619 XtFree((char *)Items(spin));
2620 Items(spin) = (XmString *)NULL;
2622 ItemCount(spin) = total_items;
2625 SetMaximumLabelSize(spin_p);
2626 if (Editable(spin) == FALSE) {
2627 ClearShadow(spin, TRUE);
2628 if (RecomputeSize(spin))
2629 SetSpinBoxSize(spin);
2630 LayoutChildren(spin);
2635 /* Update the text-field or label */
2637 SetTextFieldData(spin);
2645 * Make the given item the currently visible item in the
2646 * text-field or label.
2649 DtSpinBoxSetItem( Widget spinw,
2652 DtSpinBoxWidget spin = (DtSpinBoxWidget)spinw;
2654 _DtWidgetToAppContext(spinw);
2657 if (item && ItemCount(spin)>0) {
2658 for (i = 0; i < ItemCount(spin); i++)
2659 if (XmStringCompare(item, (Items(spin))[i]))
2661 if (i < ItemCount(spin)) {
2664 SetTextFieldData(spin);
2669 XtWarning(SB_SET_ITEM);
2672 XtWarning(SB_SET_ITEM);