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 libraries 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 /*Support for a legacy operating system has resulted in some leftover cruft
92 * code which wasn't ifdefed out, this needs to be cleaned, such code is
93 * marked Legacy: - 05/19/18 - C
96 #include <Dt/DtMsgsP.h>
99 #include <Xm/RepType.h>
100 #include "SpinBoxP.h"
101 #include "DtWidgetI.h"
103 #include <Xm/XmPrivate.h> /* _XmShellIsExclusive */
106 #include <langinfo.h>
113 #define DtSpinBoxIndex (XmManagerIndex + 1)
114 static XmOffsetPtr ipot; /* Instance part offset table */
115 static XmOffsetPtr cpot; /* Constraint part offset table */
117 static void ClassInitialize ();
118 static void Initialize (DtSpinBoxWidget request,
119 DtSpinBoxWidget new, ArgList given_args,
121 static XmNavigability WidgetNavigable (DtSpinBoxWidget spin);
122 static void _SpinBoxFocusIn (DtSpinBoxWidget spin, XEvent *event,
123 char **params, Cardinal *num_params);
124 static void _SpinBoxFocusOut (DtSpinBoxWidget spin, XEvent *event,
125 char **params, Cardinal *num_params);
126 static void DrawHighlight (DtSpinBoxWidget spin, Boolean clear);
127 static void _SpinBoxUp (DtSpinBoxWidget spin,
128 XEvent *event, char **params,
129 Cardinal *num_params);
130 static void _SpinBoxDown (DtSpinBoxWidget spin,
131 XEvent *event, char **params,
132 Cardinal *num_params);
133 static void _SpinBoxLeft (DtSpinBoxWidget spin,
134 XEvent *event, char **params,
135 Cardinal *num_params);
136 static void _SpinBoxRight (DtSpinBoxWidget spin,
137 XEvent *event, char **params,
138 Cardinal *num_params);
139 static void _SpinBoxBeginLine (DtSpinBoxWidget spin,
140 XEvent *event, char **params,
141 Cardinal *num_params);
142 static void _SpinBoxEndLine (DtSpinBoxWidget spin,
143 XEvent *event, char **params,
144 Cardinal *num_params);
145 static void _SpinBoxGetFocus (DtSpinBoxWidget spin,
146 XEvent *event, char **params,
147 Cardinal *num_params);
148 static void _SpinBoxPrevTabGroup (DtSpinBoxWidget spin,
149 XEvent *event, char **params,
150 Cardinal *num_params);
151 static void _SpinBoxNextTabGroup (DtSpinBoxWidget spin,
152 XEvent *event, char **params,
153 Cardinal *num_params);
155 static void CheckResources (DtSpinBoxWidget spin);
156 static void Destroy (DtSpinBoxWidget spin);
157 static void Resize (DtSpinBoxWidget spin);
158 static void Redisplay (DtSpinBoxWidget w, XEvent *event,
160 static XtGeometryResult GeometryManager (Widget w,
161 XtWidgetGeometry *request,
162 XtWidgetGeometry *reply);
163 static void SetSpinBoxSize (DtSpinBoxWidget spin);
164 static void ForceChildSizes (DtSpinBoxWidget spin);
165 static void CalculateSizes (DtSpinBoxWidget spin,
168 Dimension *parrow_width);
169 static void LayoutChildren (DtSpinBoxWidget spin);
170 static Boolean SetValues (DtSpinBoxWidget current,
171 DtSpinBoxWidget request,
172 DtSpinBoxWidget new);
173 static void ClearShadow (DtSpinBoxWidget w, Boolean all);
174 static void DrawShadow (DtSpinBoxWidget w);
175 static void StoreResourceInfo (DtSpinBoxPart *spin_p,
176 DtSpinBoxPart *old_p,
178 static char* GetTextString (XmString xm_string);
179 static void SetTextFieldData (DtSpinBoxWidget spin);
180 static void SetMaximumLabelSize (DtSpinBoxPart *spin_p);
181 static void SetLabelData (DtSpinBoxWidget spin);
182 static void timer_dispatch (XtPointer client_data, XtIntervalId *id);
183 static void TextFieldActivate (DtSpinBoxPart *spin_p);
184 static Boolean SendCallback (DtSpinBoxWidget spin, XEvent *event,
185 Boolean value_changed, int position,
186 float current, Boolean crossed);
187 static void FinishUpDown (DtSpinBoxWidget spin,
188 XtPointer arrow_call_data, int new_position,
189 float new_current, Boolean crossed);
190 static void up_cb (Widget w, XtPointer client_data,
191 XtPointer call_data);
192 static void down_cb (Widget w, XtPointer client_data,
193 XtPointer call_data);
194 static void disarm_cb (Widget w, XtPointer client_data,
195 XtPointer call_data);
196 static void grab_leave_cb (Widget w, XtPointer client_data,
197 XEvent *event, Boolean *dispatch);
198 static void text_losing_focus_cb (Widget w, XtPointer client_data,
199 XtPointer call_data);
200 static void text_activate_cb (Widget w, XtPointer client_data,
201 XtPointer call_data);
202 static void text_focus_cb (Widget w, XtPointer client_data,
203 XtPointer call_data);
204 static XmImportOperator _XmSetSyntheticResForChild (Widget widget,
208 static XmString InitLabel = NULL;
213 #define Label(w) XmField(w,ipot,DtSpinBox,label,Widget)
214 #define UpArrow(w) XmField(w,ipot,DtSpinBox,up_arrow,Widget)
215 #define DownArrow(w) XmField(w,ipot,DtSpinBox,down_arrow,Widget)
216 #define WhichArrow(w) XmField(w,ipot,DtSpinBox,which_arrow,unsigned char)
217 #define InitCb(w) XmField(w,ipot,DtSpinBox,init_cb,Boolean)
218 #define Grabbed(w) XmField(w,ipot,DtSpinBox,grabbed,Boolean)
219 #define Base(w) XmField(w,ipot,DtSpinBox,base,int)
220 #define Min(w) XmField(w,ipot,DtSpinBox,min,float)
221 #define Max(w) XmField(w,ipot,DtSpinBox,max,float)
222 #define Increment(w) XmField(w,ipot,DtSpinBox,increment,float)
223 #define Current(w) XmField(w,ipot,DtSpinBox,current,float)
224 #define FloatFormat(w) (String) &(XmField(w,ipot,DtSpinBox,float_format,char *))
225 #define OldWidth(w) XmField(w,ipot,DtSpinBox,old_width,Dimension)
226 #define OldHeight(w) XmField(w,ipot,DtSpinBox,old_height,Dimension)
227 #define LabelMaxLength(w) XmField(w,ipot,DtSpinBox,label_max_length,Dimension)
228 #define LabelMaxHeight(w) XmField(w,ipot,DtSpinBox,label_max_height,Dimension)
230 #define ArrowSensitivity(w) XmField(w,ipot,DtSpinBox,arrow_sensitivity,unsigned char)
231 #define DecimalPoints(w) XmField(w,ipot,DtSpinBox,decimal_points,short)
232 #define NumericIncrement(w) XmField(w,ipot,DtSpinBox,numeric_increment,int)
233 #define Maximum(w) XmField(w,ipot,DtSpinBox,maximum,int)
234 #define Minimum(w) XmField(w,ipot,DtSpinBox,minimum,int)
235 #define ItemCount(w) XmField(w,ipot,DtSpinBox,item_count,int)
236 #define Position(w) XmField(w,ipot,DtSpinBox,position,int)
237 #define ChildType(w) XmField(w,ipot,DtSpinBox,child_type,unsigned char)
238 #define Items(w) XmField(w,ipot,DtSpinBox,items,XmStringTable)
239 #define ActivateCallback(w) XmField(w,ipot,DtSpinBox,activate_callback,XtCallbackList)
240 #define Alignment(w) XmField(w,ipot,DtSpinBox,alignment,unsigned char)
241 #define ArrowLayout(w) XmField(w,ipot,DtSpinBox,arrow_layout,unsigned char)
242 #define ArrowSize(w) XmField(w,ipot,DtSpinBox,arrow_size,Dimension)
243 #define TextColumns(w) XmField(w,ipot,DtSpinBox,text_columns,short)
244 #define Editable(w) XmField(w,ipot,DtSpinBox,editable,Boolean)
245 #define FocusCallback(w) XmField(w,ipot,DtSpinBox,focus_callback,XtCallbackList)
246 #define InitialDelay(w) XmField(w,ipot,DtSpinBox,initial_delay,unsigned int)
247 #define LosingFocusCallback(w) XmField(w,ipot,DtSpinBox,losing_focus_callback,XtCallbackList)
248 #define MarginHeight(w) XmField(w,ipot,DtSpinBox,margin_height,Dimension)
249 #define MarginWidth(w) XmField(w,ipot,DtSpinBox,margin_width,Dimension)
250 #define TextMaxLength(w) XmField(w,ipot,DtSpinBox,text_max_length,int)
251 #define ModifyVerifyCallback(w) XmField(w,ipot,DtSpinBox,modify_verify_callback,XtCallbackList)
252 #define RecomputeSize(w) XmField(w,ipot,DtSpinBox,recompute_size,Boolean)
253 #define RepeatDelay(w) XmField(w,ipot,DtSpinBox,repeat_delay,unsigned int)
254 #define Text(w) XmField(w,ipot,DtSpinBox,text,Widget)
255 #define ValueChangedCallback(w) XmField(w,ipot,DtSpinBox,value_changed_callback,XtCallbackList)
256 #define Wrap(w) XmField(w,ipot,DtSpinBox,wrap,Boolean)
257 #define Timer(w) XmField(w,ipot,DtSpinBox,timer,XtIntervalId)
259 /* SpinBox and Superclass resource macros*/
260 #define PUnitType(w) w->primitive.unit_type
261 #define MUnitType(w) w->manager.unit_type
262 #define MFgPixel(w) w->manager.foreground
263 #define SPIN_SHADOW(w) w->manager.shadow_thickness
264 #define CBgPixel(w) w->core.background_pixel
265 #define CBgPixmap(w) w->core.background_pixmap
266 #define Width(w) w->core.width
267 #define Height(w) w->core.height
268 #define SPIN_MARGIN_W(w) MarginWidth(w)
269 #define SPIN_MARGIN_H(w) MarginHeight(w)
270 #define MAXINT 2147483647 /* Taken from TextF.c */
271 #define DEFAULT_COL 20
273 /* Legacy: Label get Focus */
274 static XtTranslations child_trans_label;
275 /* Legacy: Keyboard only for Text */
276 static XtTranslations child_trans_text;
278 static XtTranslations child_trans_arrow;
280 static XtTranslations child_trans;
281 static XtTranslations spin_trans;
284 static char const SpinBoxTranslationTable[] = "\
285 <FocusIn>: SpinBoxFocusIn() \n\
286 <FocusOut>: SpinBoxFocusOut() \n\
287 <Key>osfUp: SpinBoxUp() \n\
288 <Key>osfDown: SpinBoxDown() \n\
289 <Key>osfRight: SpinBoxRight() \n\
290 <Key>osfLeft: SpinBoxLeft() \n\
291 <Key>osfBeginLine: SpinBoxBeginLine() \n\
292 <Key>osfEndLine: SpinBoxEndLine() \n\
295 static char const SpinBoxChildTranslationTable[] = "\
296 <Key>osfUp: SpinBoxUp(child) \n\
297 <Key>osfDown: SpinBoxDown(child) \n\
298 <Key>osfRight: SpinBoxRight(child) \n\
299 <Key>osfLeft: SpinBoxLeft(child) \n\
300 <Key>osfBeginLine: SpinBoxBeginLine(child) \n\
301 <Key>osfEndLine: SpinBoxEndLine(child) \n\
304 /* #5: Label get focus */
305 static char const SpinBoxLabelTranslationTable[] = "\
306 <Key>osfUp: SpinBoxUp(child) \n\
307 <Key>osfDown: SpinBoxDown(child) \n\
308 <Key>osfRight: SpinBoxRight(child) \n\
309 <Key>osfLeft: SpinBoxLeft(child) \n\
310 <Key>osfBeginLine: SpinBoxBeginLine(child) \n\
311 <Key>osfEndLine: SpinBoxEndLine(child) \n\
312 <Key>osfDown: SpinBoxGetFocus() \n\
313 <Btn1Down>,<Btn1Up>: SpinBoxGetFocus() \n\
314 <Key>osfSelect: SpinBoxGetFocus() \n\
315 ~s ~m ~a <Key>space: SpinBoxGetFocus() \n\
318 /* Legacy: Keyboard Only Traversing During Editable-Mode */
319 static char const SpinBoxTextTranslationTable[] = "\
320 <Key>osfUp: SpinBoxUp(child) SpinBoxRight(child)\n\
321 <Key>osfDown: SpinBoxDown(child) SpinBoxLeft(child)\n\
323 static char const SpinBoxArrowTranslationTable[] = "\
324 <Key>osfUp: SpinBoxUp(child) \n\
325 <Key>osfDown: SpinBoxDown(child) \n\
326 <Key>osfRight: SpinBoxRight(child) \n\
327 <Key>osfLeft: SpinBoxLeft(child) \n\
328 <Key>osfBeginLine: SpinBoxBeginLine(child) \n\
329 <Key>osfEndLine: SpinBoxEndLine(child) \n\
330 s ~m ~a <Key>Tab: SpinBoxPrevTabGroup()\n\
331 ~m ~a <Key>Tab: SpinBoxNextTabGroup()\n\
335 static XtActionsRec SpinBoxActionTable[] = {
336 {"SpinBoxFocusIn", (XtActionProc)_SpinBoxFocusIn},
337 {"SpinBoxFocusOut", (XtActionProc)_SpinBoxFocusOut},
338 {"SpinBoxUp", (XtActionProc)_SpinBoxUp},
339 {"SpinBoxDown", (XtActionProc)_SpinBoxDown},
340 {"SpinBoxRight", (XtActionProc)_SpinBoxRight},
341 {"SpinBoxLeft", (XtActionProc)_SpinBoxLeft},
342 {"SpinBoxBeginLine", (XtActionProc)_SpinBoxBeginLine},
343 {"SpinBoxEndLine", (XtActionProc)_SpinBoxEndLine},
344 {"SpinBoxGetFocus", (XtActionProc)_SpinBoxGetFocus},
345 {"SpinBoxPrevTabGroup", (XtActionProc)_SpinBoxPrevTabGroup},
346 {"SpinBoxNextTabGroup", (XtActionProc)_SpinBoxNextTabGroup},
349 /* DtSpinBoxWidget resources */
351 #define offset(field) XtOffset(DtSpinBoxWidget, field)
352 #define DtOffset(field) XmPartOffset(DtSpinBox,field)
353 static XmPartResource resources[] = {
354 {XmNshadowThickness, XmCShadowThickness, XmRHorizontalDimension,
355 sizeof(Dimension), offset(manager.shadow_thickness),
356 XmRImmediate, (XtPointer)TEXT_FIELD_SHADOW},
358 /* Common resources */
359 {DtNactivateCallback, DtCCallback, XmRCallback, sizeof(XtCallbackList),
360 DtOffset(activate_callback), XmRCallback,
362 {DtNalignment, DtCAlignment, XmRAlignment, sizeof(unsigned char),
363 DtOffset(alignment), XmRImmediate,
364 (XtPointer)DtALIGNMENT_BEGINNING},
365 {DtNarrowLayout, DtCArrowLayout, DtRArrowLayout, sizeof(unsigned char),
366 DtOffset(arrow_layout), XmRImmediate,
367 (XtPointer)DtARROWS_END},
368 {DtNarrowSensitivity, DtCArrowSensitivity, DtRArrowSensitivity,
369 sizeof(unsigned char), DtOffset(arrow_sensitivity),
370 XmRImmediate, (XtPointer)DtARROWS_SENSITIVE},
371 {DtNspinBoxChildType, DtCSpinBoxChildType, DtRSpinBoxChildType,
372 sizeof(unsigned char),
373 DtOffset(child_type), XmRImmediate, (XtPointer)DtSTRING},
374 {DtNcolumns, DtCColumns, XmRShort, sizeof(short),
375 DtOffset(text_columns), XmRImmediate, (XtPointer)DEFAULT_COL},
376 {DtNdecimalPoints, DtCDecimalPoints, XmRShort, sizeof( short ),
377 DtOffset(decimal_points), XmRImmediate, (XtPointer)0},
378 {DtNeditable, DtCEditable, XmRBoolean, sizeof(Boolean),
379 DtOffset(editable), XmRImmediate, (XtPointer)TRUE},
380 {DtNfocusCallback, DtCCallback, XmRCallback, sizeof(XtCallbackList),
381 DtOffset(focus_callback), XmRCallback,
383 {DtNincrementValue, DtCIncrementValue, XmRInt, sizeof(int),
384 DtOffset(numeric_increment), XmRImmediate, (XtPointer)1},
385 {DtNinitialDelay, DtCInitialDelay, XmRInt, sizeof(unsigned int),
386 DtOffset(initial_delay), XmRImmediate, (XtPointer)250},
387 {DtNnumValues, DtCNumValues, DtRNumValues, sizeof(int),
388 DtOffset(item_count), XmRImmediate, (XtPointer)0},
389 {DtNvalues, DtCItems, XmRXmStringTable, sizeof(XmStringTable),
390 DtOffset(items), XmRImmediate, (XtPointer)NULL},
391 {DtNlosingFocusCallback, DtCCallback, XmRCallback, sizeof(XtCallbackList),
392 DtOffset(losing_focus_callback), XmRCallback,
394 {DtNmarginHeight, DtCMarginHeight, XmRVerticalDimension, sizeof(Dimension),
395 DtOffset(margin_height), XmRImmediate, (XtPointer)MARGIN},
396 {DtNmarginWidth, DtCMarginWidth, XmRHorizontalDimension, sizeof(Dimension),
397 DtOffset(margin_width), XmRImmediate, (XtPointer)MARGIN},
398 {DtNmaximumValue, DtCMaximumValue, XmRInt, sizeof(int),
399 DtOffset(maximum), XmRImmediate, (XtPointer)10},
400 {DtNmaxLength, DtCMaxLength, XmRInt, sizeof(int),
401 DtOffset(text_max_length), XmRImmediate, (XtPointer)MAXINT},
402 {DtNminimumValue, DtCMinimumValue, XmRInt, sizeof(int),
403 DtOffset(minimum), XmRImmediate, (XtPointer)0},
404 {DtNmodifyVerifyCallback, DtCCallback, XmRCallback,
405 sizeof(XtCallbackList), DtOffset(modify_verify_callback),
406 XmRCallback, (XtPointer)NULL},
407 {DtNposition, DtCPosition, XmRInt, sizeof(int),
408 DtOffset(position), XmRImmediate, (XtPointer)0},
409 {DtNrecomputeSize, DtCRecomputeSize, XmRBoolean, sizeof(Boolean),
410 DtOffset(recompute_size), XmRImmediate, (XtPointer)TRUE},
411 {DtNrepeatDelay, DtCRepeatDelay, XmRInt, sizeof(unsigned int),
412 DtOffset(repeat_delay), XmRImmediate, (XtPointer)200},
413 {DtNtextField, DtCTextField, XmRWidget, sizeof(Widget),
414 DtOffset(text), XmRImmediate, (XtPointer)NULL},
415 {DtNvalueChangedCallback, DtCCallback, XmRCallback,
416 sizeof(XtCallbackList), DtOffset(value_changed_callback),
417 XmRCallback, (XtPointer)NULL},
418 {DtNwrap, DtCWrap, XmRBoolean, sizeof(Boolean),
419 DtOffset(wrap), XmRImmediate, (XtPointer)TRUE},
422 /* Synthetic resources. Only used for Motif API arrowSize right now */
423 static XmSyntheticResource syn_resources[] = {
424 {DtNarrowSize, sizeof(Dimension), DtOffset(arrow_size),
425 _DtSpinBoxGetArrowSize, _XmSetSyntheticResForChild},
426 {DtNmarginHeight, sizeof(Dimension), DtOffset(margin_height),
427 XmeFromVerticalPixels, XmeToVerticalPixels},
428 {DtNmarginWidth, sizeof(Dimension), DtOffset(margin_width),
429 XmeFromHorizontalPixels, XmeToHorizontalPixels},
434 /* Need Class Extension for widget navigation */
435 static XmBaseClassExtRec baseClassExtRec = {
438 XmBaseClassExtVersion,
439 sizeof(XmBaseClassExtRec),
440 (XtInitProc)NULL, /* InitializePrehook */
441 (XtSetValuesFunc)NULL, /* SetValuesPrehook */
442 (XtInitProc)NULL, /* InitializePosthook */
443 (XtSetValuesFunc)NULL, /* SetValuesPosthook */
444 NULL, /* secondaryObjectClass */
445 (XtInitProc)NULL, /* secondaryCreate */
446 (XmGetSecResDataFunc)NULL, /* getSecRes data */
447 { 0 }, /* fastSubclass flags */
448 (XtArgsProc)NULL, /* getValuesPrehook */
449 (XtArgsProc)NULL, /* getValuesPosthook */
450 (XtWidgetClassProc)NULL, /* classPartInitPrehook */
451 (XtWidgetClassProc)NULL, /* classPartInitPosthook*/
452 NULL, /* ext_resources */
453 NULL, /* compiled_ext_resources*/
454 0, /* num_ext_resources */
455 FALSE, /* use_sub_resources */
456 (XmWidgetNavigableProc)WidgetNavigable,
457 /* widgetNavigable */
458 (XmFocusChangeProc)NULL, /* focusChange */
459 (XmWrapperData)NULL /* wrapperData */
463 * Define Class Record.
465 externaldef(dtspinboxclassrec) DtSpinBoxClassRec dtSpinBoxClassRec =
467 { /* core_class fields */
468 (WidgetClass)&(xmManagerClassRec), /* superclass */
469 (String)"DtSpinBox", /* class_name */
470 (Cardinal)sizeof(DtSpinBoxPart), /* widget_size */
471 (XtProc)ClassInitialize, /* class_initialize */
472 (XtWidgetClassProc)NULL, /* class_part_init */
473 (XtEnum)FALSE, /* class_inited */
474 (XtInitProc)Initialize, /* initialize */
475 (XtArgsProc)NULL, /* initialize_hook */
476 (XtRealizeProc)XtInheritRealize, /* realize */
477 (XtActionList)SpinBoxActionTable, /* actions */
478 (Cardinal)XtNumber(SpinBoxActionTable), /* num_actions */
479 (XtResourceList)resources, /* resources */
480 (Cardinal)XtNumber(resources), /* num_resources */
481 (XrmClass)NULLQUARK, /* xrm_class */
482 (Boolean)TRUE, /* compress_motion */
483 (XtEnum)XtExposeCompressMaximal, /* compress_exposure */
484 (Boolean)TRUE, /* compress_enterleave*/
485 (Boolean)FALSE, /* visible_interest */
486 (XtWidgetProc)Destroy, /* destroy */
487 (XtWidgetProc)Resize, /* resize */
488 (XtExposeProc)Redisplay, /* expose */
489 (XtSetValuesFunc)SetValues, /* set_values */
490 (XtArgsFunc)NULL, /* set values hook */
491 (XtAlmostProc)XtInheritSetValuesAlmost, /* set values almost */
492 (XtArgsProc)NULL, /* get values hook */
493 (XtAcceptFocusProc)NULL, /* accept_focus */
494 (XtVersionType)XtVersionDontCheck, /* Version */
495 (XtPointer)NULL, /* PRIVATE cb list */
496 (String)XtInheritTranslations, /* tm_table */
497 (XtGeometryHandler)XtInheritQueryGeometry, /* query_geom */
498 (XtStringProc)XtInheritDisplayAccelerator, /* display_accelerator*/
499 (XtPointer)&baseClassExtRec /* extension */
501 { /* composite_class fields */
502 (XtGeometryHandler)GeometryManager, /* geometry_manager */
503 (XtWidgetProc)XtInheritChangeManaged, /* change_managed */
504 (XtWidgetProc)XtInheritInsertChild, /* insert_child */
505 (XtWidgetProc)XtInheritDeleteChild, /* delete_child */
506 (XtPointer)NULL /* extension */
508 { /* constraint_class fields */
509 (XtResourceList)NULL, /* resources */
510 (Cardinal)0, /* num_resources */
511 (Cardinal)0, /* constraint_size */
512 (XtInitProc)NULL, /* initialize */
513 (XtWidgetProc)NULL, /* destroy */
514 (XtSetValuesFunc)NULL, /* set_values */
515 (XtPointer)NULL /* extension */
517 { /* manager class */
518 (String)XtInheritTranslations, /* translations */
519 (XmSyntheticResource*)syn_resources, /* syn resources */
520 (int)XtNumber(syn_resources), /* num syn_resources */
521 (XmSyntheticResource*)NULL, /* get_cont_resources */
522 (int)0, /* num_get_cont_resources */
523 (XmParentProcessProc)XmInheritParentProcess,/* parent_process */
524 (XtPointer)NULL /* extension */
526 { /* spin_box_class fields */
531 externaldef(dtspinboxwidgetclass) WidgetClass dtSpinBoxWidgetClass =
532 (WidgetClass)&dtSpinBoxClassRec;
534 static XmRepTypeId _DtRID_SB_ARROW_SENSITIVITY_TYPE;
535 static String _DtArrowSensitivityNames[] = {
536 "arrows_insensitive",
537 "arrows_increment_sensitive",
538 "arrows_decrement_sensitive",
543 * Must set up the record type for the class extensions to work.
546 ClassInitialize(void)
548 baseClassExtRec.record_type = XmQmotif;
552 XmResolveAllPartOffsets(dtSpinBoxWidgetClass, &ipot, &cpot);
554 child_trans = XtParseTranslationTable(SpinBoxChildTranslationTable);
555 spin_trans = XtParseTranslationTable(SpinBoxTranslationTable);
557 child_trans_label=XtParseTranslationTable(SpinBoxLabelTranslationTable);
558 child_trans_text=XtParseTranslationTable(SpinBoxTextTranslationTable);
559 child_trans_arrow=XtParseTranslationTable(SpinBoxArrowTranslationTable);
561 _DtRID_SB_ARROW_SENSITIVITY_TYPE =
562 XmRepTypeRegister(DtRArrowSensitivity, _DtArrowSensitivityNames,
563 NULL, XtNumber(_DtArrowSensitivityNames));
565 InitLabel = XmStringCreateLocalized(SB_LABEL);
569 * SpinBox initialization function. This builds the widgets inside
570 * our widget, to get the correct layout. If the editable resource
571 * is TRUE, we create a textField; if FALSE, we create a label. If the
572 * user changes this resource later, we will create the other widget
573 * (textField or Label). We don't want to carry backage from both
574 * widgets if the user never changes the editable resource.
577 Initialize( DtSpinBoxWidget request,
582 DtSpinBoxPart *spin_p = (DtSpinBoxPart*)
583 &(XmField(new,ipot,DtSpinBox,label,Widget));
587 /* Resolution Independent */
588 unsigned char unit_type = MUnitType(new);
590 /* Overwrite the manager's focusIn and focusOut translations */
591 XtOverrideTranslations((Widget)new, spin_trans);
593 widget_name = XtMalloc(strlen(XtName((Widget)new)) + 10);
595 Text(new) = (Widget)NULL;
596 Label(new) = (Widget)NULL;
600 Grabbed(new) = FALSE;
605 * Create the text or label depending on editable resource.
608 sprintf(widget_name, "%s_TF", XtName((Widget)new));
610 XtSetArg(args[n], XmNmaxLength, TextMaxLength(new)); n++;
611 XtSetArg(args[n], XmNmarginWidth, TEXT_CONTEXT_MARGIN); n++;
612 XtSetArg(args[n], XmNmarginHeight, 2); n++;
613 /* Resolution Independent */
614 if (unit_type != XmPIXELS) {
615 XtSetArg(args[n], XmNunitType, XmPIXELS); n++;
617 Text(new) = XtCreateManagedWidget(widget_name,
618 xmTextFieldWidgetClass,
619 (Widget)new, args, n);
620 XtAddCallback(Text(new), XmNlosingFocusCallback,
621 text_losing_focus_cb, (XtPointer)new);
622 XtAddCallback(Text(new), XmNactivateCallback,
623 text_activate_cb, (XtPointer)new);
624 XtAddCallback(Text(new), XmNfocusCallback,
625 text_focus_cb, (XtPointer)new);
627 if (TextColumns(request) == DEFAULT_COL && Width(request)) {
629 CalculateSizes(new, &width, NULL, NULL);
630 XtSetArg(args[n], XmNwidth, width); n++;
633 XtSetArg(args[n], XmNcolumns, TextColumns(new)); n++;
635 if (unit_type != XmPIXELS) {
636 XtSetArg(args[n], XmNunitType, unit_type); n++;
638 XtSetValues(Text(new), args, n);
641 sprintf(widget_name, "%s_Label", XtName((Widget)new));
642 SPIN_SHADOW(new) = LABEL_SHADOW;
644 XtSetArg(args[n], XmNalignment, Alignment(new)); n++;
645 XtSetArg(args[n], XmNrecomputeSize, FALSE); n++;
646 XtSetArg(args[n], XmNlabelString, InitLabel); n++;
647 XtSetArg(args[n], XmNmarginLeft, LABEL_PADDING); n++;
648 XtSetArg(args[n], XmNmarginRight, LABEL_PADDING); n++;
649 XtSetArg(args[n], XmNmarginWidth, TEXT_CONTEXT_MARGIN); n++;
650 XtSetArg(args[n], XmNmarginHeight, 2); n++;
651 if (unit_type != XmPIXELS) {
652 XtSetArg(args[n], XmNunitType, XmPIXELS); n++;
654 Label(new) = XtCreateManagedWidget(widget_name, xmLabelWidgetClass,
655 (Widget)new, args, n);
657 if (unit_type != XmPIXELS) {
658 XtSetArg(args[n], XmNunitType, unit_type); n++;
662 CalculateSizes(new, &width, NULL, NULL);
663 XtSetArg(args[n], XmNwidth, width); n++;
666 XtSetValues(Label(new), args, n);
670 * Create the 2 ArrowWidgets.
672 sprintf(widget_name, "%s_Up", XtName((Widget)new));
674 if (ArrowLayout(new) == DtARROWS_SPLIT) {
675 XtSetArg(args[n], XmNarrowDirection, XmARROW_RIGHT); n++;
677 XtSetArg(args[n], XmNhighlightThickness, 0); n++;
678 XtSetArg(args[n], XmNshadowThickness, 0); n++;
679 XtSetArg(args[n], XmNtraversalOn, FALSE); n++;
680 XtSetArg(args[n], XmNforeground, CBgPixel(new)); n++;
681 UpArrow(new) = XtCreateManagedWidget(widget_name,
682 xmArrowButtonWidgetClass,
683 (Widget)new, args, n);
684 XtOverrideTranslations((Widget)UpArrow(new), child_trans_arrow);
686 sprintf(widget_name, "%s_Down", XtName((Widget)new));
687 if (ArrowLayout(new) == DtARROWS_SPLIT) {
688 XtSetArg(args[n], XmNarrowDirection, XmARROW_LEFT); n++;
691 XtSetArg(args[n], XmNarrowDirection, XmARROW_DOWN); n++;
693 DownArrow(new) = XtCreateManagedWidget(widget_name,
694 xmArrowButtonWidgetClass,
695 (Widget)new, args, n);
696 XtOverrideTranslations((Widget)DownArrow(new), child_trans_arrow);
698 /* Set sensitivity of arrows (up arrow is right arrow) */
699 if ((ArrowSensitivity(new) == DtARROWS_INSENSITIVE) ||
700 (ArrowSensitivity(new) == DtARROWS_DECREMENT_SENSITIVE))
701 XtSetSensitive(UpArrow(new), FALSE);
702 if ((ArrowSensitivity(new) == DtARROWS_INSENSITIVE) ||
703 (ArrowSensitivity(new) == DtARROWS_INCREMENT_SENSITIVE))
704 XtSetSensitive(DownArrow(new), FALSE);
707 * Arm causes the value to change and the timer to start.
708 * Disarm (leaveNotify from grab) causes the timer to stop.
710 XtAddCallback(UpArrow(new), XmNarmCallback, up_cb, (XtPointer)new);
711 XtAddCallback(UpArrow(new), XmNdisarmCallback, disarm_cb,
713 XtAddEventHandler(UpArrow(new), LeaveWindowMask, FALSE, grab_leave_cb,
715 XtAddCallback(DownArrow(new), XmNarmCallback, down_cb, (XtPointer)new);
716 XtAddCallback(DownArrow(new), XmNdisarmCallback, disarm_cb,
718 XtAddEventHandler(DownArrow(new), LeaveWindowMask, FALSE,
719 grab_leave_cb, (XtPointer)new);
721 /* Initialize everything based on what the resource values are */
722 StoreResourceInfo(spin_p, NULL, TRUE);
725 * Set initial value in text or label if items was specified
727 if (Editable(new) == FALSE) {
729 SetMaximumLabelSize(spin_p);
733 SetTextFieldData(new);
739 /* Store Converter for DtNmaximumValue, DtNminimumValue, DtNincrementValue,
741 XtSetTypeConverter(XmRString, DtRMaximumValue, XtCvtStringToInt, NULL, 0,
743 XtSetTypeConverter(XmRString, DtRMinimumValue, XtCvtStringToInt, NULL, 0,
745 XtSetTypeConverter(XmRString, DtRIncrementValue, XtCvtStringToInt, NULL, 0,
747 XtSetTypeConverter(XmRString, DtRNumValues, XtCvtStringToInt, NULL, 0,
750 * this is so these resources can be set uniformly through XtCreateWidget
751 * or through defaults file as *spin.backgound
755 XtSetArg(args[n],XmNbackground,CBgPixel(new));n++;
756 XtSetArg(args[n],XmNbackgroundPixmap,CBgPixmap(new));n++;
757 XtSetArg(args[n],XmNforeground,MFgPixel(new));n++;
759 XtSetValues (Text(new),args,n);
761 XtSetValues (Label(new),args,n);
763 XtSetValues (UpArrow(new),args,n);
765 XtSetValues (DownArrow(new),args,n);
771 * Allow the manager to gain focus if not editable. If editable (using
772 * text-field), then let the toolkit give focus to the text-field.
774 static XmNavigability
775 WidgetNavigable(DtSpinBoxWidget spin)
777 XmNavigationType nav_type = ((XmManagerWidget)spin)->manager.navigation_type;
779 if (spin->core.sensitive && spin->core.ancestor_sensitive &&
780 ((XmManagerWidget)spin)->manager.traversal_on) {
781 if ((nav_type == XmSTICKY_TAB_GROUP) ||
782 (nav_type == XmEXCLUSIVE_TAB_GROUP) ||
783 ((nav_type == XmTAB_GROUP) &&
784 !_XmShellIsExclusive((Widget)spin))) {
786 return(XmDESCENDANTS_TAB_NAVIGABLE);
788 return(XmTAB_NAVIGABLE);
790 return(XmDESCENDANTS_NAVIGABLE);
792 return(XmNOT_NAVIGABLE);
796 * The spin_box gets focus.
799 _SpinBoxFocusIn( DtSpinBoxWidget spin,
802 Cardinal *num_params)
804 DrawHighlight(spin, FALSE);
808 * The spin_box loses focus.
811 _SpinBoxFocusOut( DtSpinBoxWidget spin,
814 Cardinal *num_params)
816 DrawHighlight(spin, TRUE);
820 * This function gets called whenever we draw or clear the shadow (to
821 * redraw highlight during resize, etc), as well as during focus_in
822 * and focus_out events.
825 DrawHighlight( DtSpinBoxWidget spin,
830 if (XtIsRealized((Widget)spin)) {
832 rect[0].x = rect[1].x = rect[2].x = 0;
833 rect[3].x = OldWidth(spin) - SPIN_MARGIN_W(spin);
834 rect[0].y = rect[2].y = rect[3].y = 0 ;
835 rect[1].y = OldHeight(spin) - SPIN_MARGIN_H(spin);
836 rect[0].width = rect[1].width = OldWidth(spin);
837 rect[2].width = rect[3].width = SPIN_MARGIN_W(spin);
838 rect[0].height = rect[1].height = SPIN_MARGIN_H(spin);
839 rect[2].height = rect[3].height = OldHeight(spin);
840 XFillRectangles(XtDisplayOfObject((Widget)spin),
841 XtWindowOfObject((Widget)spin),
842 spin->manager.background_GC, rect, 4);
844 else if (XmGetFocusWidget((Widget)spin) == (Widget)spin) {
845 rect[0].x = rect[1].x = rect[2].x = 0;
846 rect[3].x = XtWidth(spin) - SPIN_MARGIN_W(spin);
847 rect[0].y = rect[2].y = rect[3].y = 0 ;
848 rect[1].y = XtHeight(spin) - SPIN_MARGIN_H(spin);
849 rect[0].width = rect[1].width = XtWidth(spin);
850 rect[2].width = rect[3].width = SPIN_MARGIN_W(spin);
851 rect[0].height = rect[1].height = SPIN_MARGIN_H(spin);
852 rect[2].height = rect[3].height = XtHeight(spin);
853 XFillRectangles(XtDisplayOfObject((Widget)spin),
854 XtWindowOfObject((Widget)spin),
855 spin->manager.highlight_GC, rect, 4);
862 * osfUp virtual key hit. Simulate hitting the up arrow.
865 _SpinBoxUp( DtSpinBoxWidget spin,
868 Cardinal *num_params)
870 if (*num_params != 0) /* params means label or arrows */
871 spin = (DtSpinBoxWidget)XtParent(spin);
873 if (ArrowLayout(spin) != DtARROWS_SPLIT) {
874 up_cb((Widget)UpArrow(spin), (XtPointer)spin, NULL);
875 disarm_cb((Widget)UpArrow(spin), (XtPointer)spin, NULL);
880 * osfDown virtual key hit. Simulate hitting the down arrow.
883 _SpinBoxDown(DtSpinBoxWidget spin,
886 Cardinal *num_params)
888 if (*num_params != 0) /* params means label or arrows */
889 spin = (DtSpinBoxWidget)XtParent(spin);
891 if (ArrowLayout(spin) != DtARROWS_SPLIT) {
892 down_cb((Widget)DownArrow(spin), (XtPointer)spin, NULL);
893 disarm_cb((Widget)DownArrow(spin), (XtPointer)spin, NULL);
898 * osfRight virtual key hit. Simulate hitting the up arrow.
901 _SpinBoxRight(DtSpinBoxWidget spin,
904 Cardinal *num_params)
906 if (*num_params != 0) /* params means label or arrows */
907 spin = (DtSpinBoxWidget)XtParent(spin);
909 if (ArrowLayout(spin) == DtARROWS_SPLIT) {
910 up_cb((Widget)UpArrow(spin), (XtPointer)spin, NULL);
911 disarm_cb((Widget)UpArrow(spin), (XtPointer)spin, NULL);
916 * osfLeft virtual key hit. Simulate hitting the down arrow.
919 _SpinBoxLeft(DtSpinBoxWidget spin,
922 Cardinal *num_params)
924 if (*num_params != 0) /* params means label or arrows */
925 spin = (DtSpinBoxWidget)XtParent(spin);
927 if (ArrowLayout(spin) == DtARROWS_SPLIT) {
928 down_cb((Widget)DownArrow(spin), (XtPointer)spin, NULL);
929 disarm_cb((Widget)DownArrow(spin), (XtPointer)spin, NULL);
934 * osfBeginLine virtual key hit. Go to first item.
937 _SpinBoxBeginLine( DtSpinBoxWidget spin,
940 Cardinal *num_params)
945 if (*num_params != 0) /* params means label or arrows */
946 spin = (DtSpinBoxWidget)XtParent(spin);
948 if (ChildType(spin) == DtNUMERIC) {
949 new_position = Minimum(spin);
950 new_current = Min(spin);
955 if (SendCallback(spin, event, FALSE, new_position,
956 new_current, FALSE) == TRUE) {
957 /* User said yes, so set widget values */
958 Position(spin) = new_position;
959 Current(spin) = new_current;
961 SetTextFieldData(spin);
965 /* send value_changed callback */
966 (void)SendCallback(spin, event, TRUE, Position(spin),
967 Current(spin), FALSE);
972 * osfEndLine virtual key hit. Go to last item.
975 _SpinBoxEndLine( DtSpinBoxWidget spin,
978 Cardinal *num_params)
983 if (*num_params != 0) /* params means label or arrows */
984 spin = (DtSpinBoxWidget)XtParent(spin);
986 if (ChildType(spin) == DtNUMERIC) {
987 new_position = Maximum(spin);
988 new_current = Max(spin);
991 new_position = ItemCount(spin) - 1;
993 if (SendCallback(spin, event, FALSE, new_position,
994 new_current, FALSE) == TRUE) {
995 /* User said yes, so set widget values */
996 Position(spin) = new_position;
997 Current(spin) = new_current;
999 SetTextFieldData(spin);
1003 /* send value_changed callback */
1004 (void)SendCallback(spin, event, TRUE, Position(spin),
1005 Current(spin), FALSE);
1009 * Legacy: Get Focus for SpinBox when hit its label part
1012 _SpinBoxGetFocus( DtSpinBoxWidget spin,
1015 Cardinal *num_params)
1017 XmProcessTraversal((Widget)XtParent(spin),
1018 (XmTraversalDirection) XmTRAVERSE_CURRENT);
1022 * Legacy: Process Focus Traversal for SpinBox when cursor is in its arrow part
1025 _SpinBoxPrevTabGroup(DtSpinBoxWidget spin,
1028 Cardinal *num_params)
1030 XmProcessTraversal((Widget)XtParent(spin),
1031 (XmTraversalDirection) XmTRAVERSE_PREV_TAB_GROUP);
1035 _SpinBoxNextTabGroup(DtSpinBoxWidget spin,
1038 Cardinal *num_params)
1040 XmProcessTraversal((Widget)XtParent(spin),
1041 (XmTraversalDirection) XmTRAVERSE_NEXT_TAB_GROUP);
1045 * This function goes through most of the resources and makes sure
1046 * they have legal values.
1049 CheckResources(DtSpinBoxWidget spin)
1051 if (!XmRepTypeValidValue(_DtRID_SB_ARROW_SENSITIVITY_TYPE,
1052 ArrowSensitivity(spin), (Widget)spin)) {
1053 XtWarning(SB_ARROW_SENSITIVE);
1054 ArrowSensitivity(spin) = DtARROWS_SENSITIVE;
1056 if ((Alignment(spin) != DtALIGNMENT_CENTER) &&
1057 (Alignment(spin) != DtALIGNMENT_BEGINNING) &&
1058 (Alignment(spin) != DtALIGNMENT_END)) {
1059 XtWarning(SB_ALIGNMENT);
1060 Alignment(spin) = DtALIGNMENT_CENTER;
1062 if (InitialDelay(spin) == 0) {
1063 XtWarning(SB_INIT_DELAY);
1064 InitialDelay(spin) = 250;
1066 if ((ArrowLayout(spin) != DtARROWS_FLAT_BEGINNING) &&
1067 (ArrowLayout(spin) != DtARROWS_FLAT_END) &&
1068 (ArrowLayout(spin) != DtARROWS_SPLIT) &&
1069 (ArrowLayout(spin) != DtARROWS_BEGINNING) &&
1070 (ArrowLayout(spin) != DtARROWS_END)) {
1071 XtWarning(SB_ARROW_LAYOUT);
1072 ArrowLayout(spin) = DtARROWS_BEGINNING;
1074 if (RepeatDelay(spin) == 0) {
1075 XtWarning(SB_REPEAT_DELAY);
1076 RepeatDelay(spin) = 200;
1078 if (ItemCount(spin) < 0) {
1079 XtWarning(SB_ITEM_COUNT);
1080 ItemCount(spin) = 0;
1082 if ((ChildType(spin) == DtSTRING) &&
1083 ((Position(spin) < 0) ||
1084 ((Position(spin) >= ItemCount(spin)) &&
1085 (ItemCount(spin) > 0)))) {
1086 XtWarning(SB_POSITION_STRING);
1089 if ((DecimalPoints(spin) < 0) ||
1090 (DecimalPoints(spin) > MAX_FLOAT_DECIMALS)) {
1091 XtWarning(SB_DECIMAL_POINTS);
1092 DecimalPoints(spin) = 0;
1094 if (Minimum(spin) > Maximum(spin)) {
1095 XtWarning(SB_MIN_MAX);
1096 Minimum(spin) = Maximum(spin);
1098 if ((ChildType(spin) == DtNUMERIC) &&
1099 ((Position(spin) < Minimum(spin)) ||
1100 (Position(spin) > Maximum(spin)) ||
1101 ((Position(spin) % NumericIncrement(spin)) != 0))) {
1102 XtWarning(SB_POSITION_NUMERIC);
1103 Position(spin) = Minimum(spin);
1109 * Destroy procedure called by the toolkit.
1112 Destroy(DtSpinBoxWidget spin)
1116 if ((int)Timer(spin))
1118 XtRemoveTimeOut(Timer(spin));
1119 Timer(spin) = (XtIntervalId)NULL;
1122 if (ItemCount(spin)>0) {
1123 for (i = 0; i < ItemCount(spin); i++) {
1124 XmStringFree((Items(spin))[i]);
1126 XtFree((char*)(Items(spin)));
1130 * Don't remove callbacks and event handlers set on the children,
1131 * this has already been done by Xt (children are cleaned up before
1138 * Resize function called by toolkit. The size of our spin-box
1139 * has already been changed. That is why we must store
1140 * old_width and old_height.
1143 Resize(DtSpinBoxWidget spin)
1145 ClearShadow(spin, TRUE);
1146 LayoutChildren(spin);
1148 OldWidth(spin) = spin->core.width;
1149 OldHeight(spin) = spin->core.height;
1154 * Redisplay function called by toolkit. The widget didn't change size,
1155 * so just redisplay the shadow.
1158 Redisplay( DtSpinBoxWidget w,
1167 * GeometryManager function called by toolkit when a child resizes/moves.
1168 * We are not allowing any changes but width/height of the text-field.
1169 * this is because the user can retrieve the text-field and make changes
1170 * that we want to honor. If they mess around with the label or arrow,
1171 * then we won't honor the request.
1172 * If the text-field requests a change, then make the change, and allow
1173 * our SetSpinBoxSize() and LayoutChildren() figure out what size will
1175 * Returning GeometryDone was suppose to tell the toolkit
1176 * that we resized the child ourselves, but the text-field had trouble
1177 * with this (its' geometry_manager wasn't called or working right?), so
1178 * we return GeometryYes.
1180 static XtGeometryResult
1181 GeometryManager(Widget w, /* child */
1182 XtWidgetGeometry *request,
1183 XtWidgetGeometry *reply)
1186 DtSpinBoxWidget spin = (DtSpinBoxWidget)XtParent(w);
1187 /* Resolution Independent */
1189 Dimension width, height, border_width;
1191 unsigned char unit_type;
1193 /* Ignore everything but text-field */
1194 if (w != Text(spin) ) {
1195 return(XtGeometryNo);
1198 /* Only allow width/height changes */
1199 if (!(request->request_mode & (CWWidth | CWHeight)))
1200 return(XtGeometryNo);
1202 /* Resolution Independent */
1203 XtSetArg(args[0], XmNunitType, &unit_type);
1204 XtGetValues(w, args, 1);
1205 if ( unit_type != XmPIXELS) {
1206 XtSetArg(args[0], XmNunitType, XmPIXELS);
1207 XtSetValues(w, args, 1);
1210 /* Set the text-field to the requested size */
1211 if (request->request_mode & CWWidth) {
1213 XtSetArg(args[n], XmNwidth, &width); n++;
1215 if (request->request_mode & CWHeight) {
1217 XtSetArg(args[n], XmNheight, &height); n++;
1220 XtSetArg(args[n], XmNborderWidth, &border_width); n++;
1221 XtGetValues(w, args, n);
1222 XtResizeWidget(w, width, height, border_width);
1223 if ( unit_type != XmPIXELS) {
1224 XtSetArg(args[0], XmNunitType, unit_type);
1225 XtSetValues(w, args, 1);
1228 ClearShadow(spin, TRUE);
1229 if (RecomputeSize(spin))
1230 SetSpinBoxSize(spin);
1231 LayoutChildren(spin);
1233 return(XtGeometryDone);
1237 * This function sets the size of the spin_box widget based on the
1238 * current size of the children. Don't worry if it doesn't work, the
1239 * children will be squeezed in later.
1242 SetSpinBoxSize(DtSpinBoxWidget spin)
1244 Widget text_holder = Editable(spin) ? Text(spin) : Label(spin);
1245 Dimension shadow = SPIN_SHADOW(spin) * 2;
1246 Dimension arrow_width, arrow_height;
1247 /* MotifBc & Resolution Independent */
1248 Dimension height, width;
1250 unsigned char unit_type = MUnitType(spin);
1253 /* Resolution Independent */
1254 if (unit_type != XmPIXELS) {
1255 XtSetArg(args[0], XmNunitType, XmPIXELS);
1256 XtSetValues((Widget)spin, args, 1);
1257 XtSetValues(text_holder, args, 1);
1260 XtSetArg(args[0], XmNheight, &height);
1261 XtSetArg(args[1], XmNwidth, &width);
1262 XtGetValues(text_holder, args, 2);
1264 * Find out how big the arrow can be (needed to get
1265 * width for text_holder).
1267 arrow_width = (Dimension)((float)height * ARROW_MULT);
1268 arrow_width = (arrow_width < ARROW_MIN) ? ARROW_MIN : arrow_width;
1270 /* Get height based on arrow width */
1271 arrow_height = arrow_width;
1272 if ((ArrowLayout(spin) == DtARROWS_BEGINNING) ||
1273 (ArrowLayout(spin) == DtARROWS_END))
1274 arrow_height += arrow_height;
1276 /* Make height bigger of 2 - arrows vs text_holder */
1277 if (arrow_height > (Dimension)height)
1278 height = arrow_height;
1280 /* If not stacked add extra width for arrows */
1281 if ((ArrowLayout(spin) != DtARROWS_BEGINNING) &&
1282 (ArrowLayout(spin) != DtARROWS_END)) {
1283 arrow_width += arrow_width;
1286 (void)XtMakeResizeRequest((Widget)spin, arrow_width +
1288 (SPIN_MARGIN_W(spin) * 2),
1289 height + shadow + (SPIN_MARGIN_H(spin) * 2),
1291 OldWidth(spin) = Width(spin);
1292 OldHeight(spin) = Height(spin);
1294 /* Resolution Independent */
1295 if (unit_type != XmPIXELS) {
1296 XtSetArg(args[0], XmNunitType, unit_type);
1297 XtSetValues((Widget)spin, args, 1);
1298 XtSetValues(text_holder, args, 1);
1303 * This function makes the text_holder (label or text-field) smaller
1304 * if the spin_box couldn't grow to the needed full size. It will
1305 * also make the text_holder grow if there is space. The textfield will
1306 * grow with the spin_box, but the label will only grow to its'
1307 * maximum size. The label will also shrink down to nothing, but the
1308 * text-field will always keep its' core height.
1311 ForceChildSizes(DtSpinBoxWidget spin)
1313 Dimension available_height, available_width, arrow_width;
1314 /* MotifBc & Resolution Independent */
1316 unsigned char unit_type = XmPIXELS;
1318 /* Resolution Independent */
1319 if (MUnitType(spin) != XmPIXELS) {
1320 unit_type = MUnitType(spin);
1321 XtSetArg(args[0], XmNunitType, XmPIXELS);
1322 XtSetValues(UpArrow(spin), args, 1);
1323 XtSetValues(DownArrow(spin), args, 1);
1324 if (Editable(spin) == False)
1325 XtSetValues(Label(spin), args, 1);
1327 XtSetValues(Text(spin), args, 1);
1330 CalculateSizes(spin, &available_width, &available_height, &arrow_width);
1332 if (Editable(spin) == FALSE) { /** label **/
1333 if (available_width > LabelMaxLength(spin))
1334 available_width = LabelMaxLength(spin);
1336 if ((available_width != (Label(spin))->core.width) ||
1337 (available_height != (Label(spin))->core.height))
1338 XtResizeWidget(Label(spin), available_width, available_height,
1339 (Label(spin))->core.border_width);
1341 else if ((Text(spin))->core.width != available_width) /** TextField **/
1342 XtResizeWidget(Text(spin), available_width,
1343 (Text(spin))->core.height,
1344 (Text(spin))->core.border_width);
1345 if ((arrow_width != UpArrow(spin)->core.width) ||
1346 ((UpArrow(spin))->core.height != arrow_width)) {
1347 available_height = (available_height < ARROW_MIN) ? ARROW_MIN :
1349 XtResizeWidget(UpArrow(spin), arrow_width, arrow_width,
1350 (UpArrow(spin))->core.border_width);
1352 if ((arrow_width != (DownArrow(spin))->core.width) ||
1353 ((DownArrow(spin))->core.height != arrow_width)) {
1354 available_height = (available_height < ARROW_MIN) ? ARROW_MIN :
1356 XtResizeWidget(DownArrow(spin), arrow_width, arrow_width,
1357 DownArrow(spin)->core.border_width);
1359 /* Resolution Independent */
1360 if (MUnitType(spin) != XmPIXELS) {
1361 XtSetArg(args[0], XmNunitType, unit_type);
1362 XtSetValues(UpArrow(spin), args, 1);
1363 XtSetValues(DownArrow(spin), args, 1);
1364 if (Editable(spin) == False)
1365 XtSetValues(Label(spin), args, 1);
1367 XtSetValues(Text(spin), args, 1);
1372 CalculateSizes (DtSpinBoxWidget spin,
1375 Dimension *parrow_width)
1377 Dimension width, height, arrow_width;
1379 /* Calculate available height for children */
1380 if ((height = spin->core.height - (SPIN_SHADOW(spin) * 2) -
1381 (SPIN_MARGIN_H(spin) * 2)) <= 0)
1384 /* Get initial available width for children */
1385 width = (spin->core.width - (SPIN_SHADOW(spin) * 2) -
1386 (SPIN_MARGIN_W(spin) * 2));
1388 /* label only grows to maximum width needed */
1389 if ((Editable(spin) == FALSE) &&
1390 (height > LabelMaxHeight(spin)))
1391 height = LabelMaxHeight(spin);
1392 else if (Editable(spin))
1393 height = (Text(spin))->core.height;
1396 * Find out how big the arrow can be (needed to get
1397 * width for text_holder).
1399 arrow_width = (Dimension)(height * ARROW_MULT);
1400 arrow_width = (arrow_width < ARROW_MIN) ? ARROW_MIN : arrow_width;
1402 /* Make sure width isn't too small or too big */
1403 if ((width -= arrow_width) <= 0)
1406 /* If not stacked subtract extra arrow */
1407 if ((ArrowLayout(spin) != DtARROWS_BEGINNING) &&
1408 (ArrowLayout(spin) != DtARROWS_END)) {
1409 width -= arrow_width;
1412 if (pwidth) *pwidth = width;
1413 if (pheight) *pheight = height;
1414 if (parrow_width) *parrow_width = arrow_width;
1418 * This function positions the children within the spin_box widget.
1419 * It calls ForceChildSizes() to make sure the children fit within the
1420 * spin_box widget, but it will not try to resize the spin_box widget.
1423 LayoutChildren(DtSpinBoxWidget spin)
1425 Widget text_holder = Editable(spin) ? Text(spin) : Label(spin);
1426 Position start_x = SPIN_SHADOW(spin) + SPIN_MARGIN_W(spin);
1427 Position start_y = SPIN_SHADOW(spin) + SPIN_MARGIN_H(spin);
1428 Dimension available_height = spin->core.height - (start_y * 2);
1429 Position y, arrow_y;
1430 Dimension arrow_height;
1431 /* Resolution Independent */
1433 unsigned char unit_type = XmPIXELS;
1435 ForceChildSizes(spin);
1437 /* Resolution Independent */
1438 if (MUnitType(spin) != XmPIXELS) {
1439 unit_type = MUnitType(spin);
1440 XtSetArg(args[0], XmNunitType, XmPIXELS);
1441 XtSetValues(UpArrow(spin), args, 1);
1442 XtSetValues(DownArrow(spin), args, 1);
1443 XtSetValues(text_holder, args, 1);
1446 /* Center text_holder within spin_box */
1447 y = available_height - text_holder->core.height;
1448 y = ((y < 0) ? 0 : y)/2 + start_y;
1450 arrow_height = (UpArrow(spin))->core.height;
1451 if ((ArrowLayout(spin) == DtARROWS_BEGINNING) ||
1452 (ArrowLayout(spin) == DtARROWS_END))
1453 arrow_height += arrow_height;
1454 arrow_y = available_height - arrow_height;
1455 arrow_y = ((arrow_y < 0) ? 0 : arrow_y)/2 + start_y;
1457 switch (ArrowLayout(spin)) {
1458 case DtARROWS_FLAT_BEGINNING:
1459 XtMoveWidget(UpArrow(spin), start_x, arrow_y);
1460 start_x += (UpArrow(spin))->core.width;
1461 XtMoveWidget(DownArrow(spin), start_x, arrow_y);
1462 start_x += (DownArrow(spin))->core.width;
1463 XtMoveWidget(text_holder, start_x, y);
1465 case DtARROWS_FLAT_END:
1466 XtMoveWidget(text_holder, start_x, y);
1468 * This start_x places arrow right after text_holder. With
1469 * labels we want the arrow at the end of the spin_box, so
1470 * the user can use recompute_size more effectively.
1471 * start_x += text_holder->core.width;
1473 start_x = (spin->core.width - start_x -
1474 (UpArrow(spin))->core.width -
1475 (DownArrow(spin))->core.width);
1476 XtMoveWidget(UpArrow(spin), start_x, arrow_y);
1477 start_x += (UpArrow(spin))->core.width;
1478 XtMoveWidget(DownArrow(spin), start_x, arrow_y);
1480 case DtARROWS_SPLIT:
1481 XtMoveWidget(DownArrow(spin), start_x, arrow_y);
1482 start_x += (DownArrow(spin))->core.width;
1483 XtMoveWidget(text_holder, start_x, y);
1484 start_x += text_holder->core.width;
1485 XtMoveWidget(UpArrow(spin), start_x, arrow_y);
1487 case DtARROWS_BEGINNING:
1488 XtMoveWidget(UpArrow(spin), start_x, arrow_y);
1489 arrow_y += (UpArrow(spin))->core.height;
1490 XtMoveWidget(DownArrow(spin), start_x, arrow_y);
1491 start_x += (DownArrow(spin))->core.width;
1492 XtMoveWidget(text_holder, start_x, y);
1495 XtMoveWidget(text_holder, start_x, y);
1497 * This start_x places arrow right after text_holder. With
1498 * labels we want the arrow at the end of the spin_box, so
1499 * the user can use recompute_size more effectively.
1500 * start_x += text_holder->core.width;
1502 start_x = spin->core.width - start_x - (UpArrow(spin))->core.width;
1503 XtMoveWidget(UpArrow(spin), start_x, arrow_y);
1504 arrow_y += (UpArrow(spin))->core.width;
1505 XtMoveWidget(DownArrow(spin), start_x, arrow_y);
1508 /* Resolution Independent */
1509 if (MUnitType(spin) != XmPIXELS) {
1510 XtSetArg(args[0], XmNunitType, unit_type);
1511 XtSetValues(UpArrow(spin), args, 1);
1512 XtSetValues(DownArrow(spin), args, 1);
1513 XtSetValues(text_holder, args, 1);
1519 * SetValues() routine for SpinBox widget. Most of the real work
1520 * is done in SetItems() and SetNumeric(). If items is set we store
1521 * our own XmStrings.
1522 * This function was built with static spin_boxs in mind, meaning that
1523 * is-numeric or editable resources won't be changed constantly. These
1524 * resources can be changed, but this function doesn't handle them in
1525 * a super-efficient manor. for example, changing child-type will cause
1526 * the label to be resize even if it isn't managed.
1529 SetValues( DtSpinBoxWidget current,
1530 DtSpinBoxWidget request,
1531 DtSpinBoxWidget new)
1533 DtSpinBoxPart *new_p = (DtSpinBoxPart*)
1534 &(XmField(new,ipot,DtSpinBox,label,Widget));
1535 DtSpinBoxPart *cur_p = (DtSpinBoxPart*)
1536 &(XmField(current,ipot,DtSpinBox,label,Widget));
1539 Boolean label_size_changed = FALSE;
1542 /* Resolution Independent */
1543 unsigned char unit_type = MUnitType(new);
1545 CheckResources(new);
1547 if (Text(new) != Text(current)) {
1549 Text(new) = Text(current);
1553 * Editable resource changed. If the widget (textField or Label)
1554 * doesn't exist, then create it.
1556 if (Editable(new) != Editable(current)) {
1557 if (Editable(new)) {
1558 XtUnmanageChild(Label(new));
1559 if (Text(new) == NULL) {
1560 widget_name = XtMalloc(strlen(XtName((Widget)new)) + 10);
1561 sprintf(widget_name, "%s_TF", XtName((Widget)new));
1563 XtSetArg(args[n], XmNcolumns, TextColumns(new)); n++;
1564 XtSetArg(args[n], XmNmaxLength, TextMaxLength(new)); n++;
1565 XtSetArg(args[n], XmNmarginWidth, 2); n++;
1566 XtSetArg(args[n], XmNmarginHeight, 2); n++;
1567 if (unit_type != XmPIXELS) {
1568 XtSetArg(args[n], XmNunitType, XmPIXELS); n++;
1570 Text(new) = XtCreateManagedWidget(widget_name,
1571 xmTextFieldWidgetClass,
1572 (Widget)new, args, n);
1573 XtAddCallback(Text(new), XmNlosingFocusCallback,
1574 text_losing_focus_cb, (XtPointer)new);
1575 XtAddCallback(Text(new), XmNactivateCallback,
1576 text_activate_cb, (XtPointer)new);
1577 XtAddCallback(Text(new), XmNfocusCallback,
1578 text_focus_cb, (XtPointer)new);
1579 XtFree(widget_name);
1580 if (unit_type != XmPIXELS) {
1581 XtSetArg(args[n], XmNunitType, unit_type); n++;
1582 XtSetValues(Text(new), args, 1);
1586 XtManageChild(Text(new));
1589 XtUnmanageChild(Text(new));
1590 if (Label(new) == NULL) {
1591 widget_name = XtMalloc(strlen(XtName((Widget)new)) + 10);
1592 sprintf(widget_name, "%s_Label", XtName((Widget)new));
1594 XtSetArg(args[n], XmNalignment, Alignment(new)); n++;
1595 XtSetArg(args[n], XmNrecomputeSize, FALSE); n++;
1596 XtSetArg(args[n], XmNlabelString, InitLabel); n++;
1597 XtSetArg(args[n], XmNmarginLeft, LABEL_PADDING); n++;
1598 XtSetArg(args[n], XmNmarginRight, LABEL_PADDING); n++;
1599 XtSetArg(args[n], XmNmarginWidth, TEXT_CONTEXT_MARGIN); n++;
1600 XtSetArg(args[n], XmNmarginHeight, 0); n++;
1601 if (unit_type != XmPIXELS) {
1602 XtSetArg(args[n], XmNunitType, XmPIXELS); n++;
1604 Label(new) = XtCreateManagedWidget(widget_name,
1606 (Widget)new, args, n);
1607 XtOverrideTranslations((Widget)Label(new), child_trans);
1608 XtFree(widget_name);
1609 if (unit_type != XmPIXELS) {
1610 XtSetArg(args[n], XmNunitType, unit_type); n++;
1611 XtSetValues(Label(new), args, 1);
1615 XtManageChild(Label(new));
1618 * Text-fields and labels have different shadows. Only
1619 * change if user didn't change the shadow resource.
1621 if (SPIN_SHADOW(new) == SPIN_SHADOW(current))
1622 SPIN_SHADOW(new) = (Editable(new)) ? TEXT_FIELD_SHADOW :
1626 /* Check arrow sensitivity (up arrow is right arrow)*/
1627 if (ArrowSensitivity(new) != ArrowSensitivity(current)) {
1628 XtSetSensitive(UpArrow(new),
1629 ((ArrowSensitivity(new) == DtARROWS_SENSITIVE) ||
1630 (ArrowSensitivity(new) == DtARROWS_INCREMENT_SENSITIVE)));
1631 XtSetSensitive(DownArrow(new),
1632 ((ArrowSensitivity(new) == DtARROWS_SENSITIVE) ||
1633 (ArrowSensitivity(new) == DtARROWS_DECREMENT_SENSITIVE)));
1637 * Check arrow layout. Only need to change arrows if going to or
1638 * from DtARROWS_SPLIT. The LayoutChildren() routine actually
1639 * positions the arrows in the correct place.
1641 if (ArrowLayout(new) != ArrowLayout(current)) {
1642 if (ArrowLayout(new) == DtARROWS_SPLIT) {
1643 XtSetArg(args[0], XmNarrowDirection, XmARROW_RIGHT);
1644 XtSetValues(UpArrow(new), args, 1);
1645 XtSetArg(args[0], XmNarrowDirection, XmARROW_LEFT);
1646 XtSetValues(DownArrow(new), args, 1);
1649 XtSetArg(args[0], XmNarrowDirection, XmARROW_UP);
1650 XtSetValues(UpArrow(new), args, 1);
1651 XtSetArg(args[0], XmNarrowDirection, XmARROW_DOWN);
1652 XtSetValues(DownArrow(new), args, 1);
1656 if (Text(new) && (Text(new) == Text(current))) {
1658 if (TextColumns(new) != TextColumns(current)) {
1659 XtSetArg(args[n], XmNcolumns, TextColumns(new)); n++;
1661 if (TextMaxLength(new) != TextMaxLength(current)) {
1662 XtSetArg(args[n], XmNmaxLength, TextMaxLength(new)); n++;
1665 XtSetValues(Text(new), args, n);
1669 * LabelWidget alignment has changed.
1671 if (Label(new) && (Alignment(new) != Alignment(current))) {
1672 XtSetArg(args[0], XmNalignment, Alignment(new));
1673 XtSetValues(Label(new), args, 1);
1676 store_info = ((Items(new) != Items(current)) ||
1677 (ItemCount(new) != ItemCount(current)) ||
1678 (DecimalPoints(new) != DecimalPoints(current)) ||
1679 (Maximum(new) != Maximum(current)) ||
1680 (Minimum(new) != Minimum(current)) ||
1681 (NumericIncrement(new) != NumericIncrement(current)) ||
1682 ((ChildType(new) == DtNUMERIC) &&
1683 (Position(new) != Position(current))));
1685 StoreResourceInfo(new_p, cur_p, (Items(new) != Items(current)));
1687 if (Label(new) && (store_info ||
1688 (Label(new) != Label(current)) ||
1689 (ChildType(new) != ChildType(current)))) {
1690 SetMaximumLabelSize(new_p);
1691 label_size_changed = TRUE;
1695 (Alignment(new) != Alignment(current)) ||
1696 (Editable(new) != Editable(current)) ||
1697 (Position(new) != Position(current)) ||
1698 (Label(new) != Label(current)) ||
1699 (ChildType(new) != ChildType(current))) {
1701 SetTextFieldData(new);
1707 * Must recalculate the spin_box and re-layout the children.
1708 * If this is not editable, then set the label to its' maximum
1709 * size; it will get chopped if it is too big. This is needed
1710 * because we shrink the label down, and SetSpinBoxSize() uses
1711 * the label's core sizes to figure what size to become.
1713 if ((Editable(new) != Editable(current)) ||
1714 (SPIN_MARGIN_W(new) != SPIN_MARGIN_W(current)) ||
1715 (SPIN_MARGIN_H(new) != SPIN_MARGIN_H(current)) ||
1716 (SPIN_SHADOW(new) != SPIN_SHADOW(current)) ||
1717 (ArrowLayout(new) != ArrowLayout(current)) ||
1718 (!(Editable(new)) && label_size_changed)) {
1719 ClearShadow(current, TRUE);
1720 if (RecomputeSize(new))
1721 SetSpinBoxSize(new);
1722 LayoutChildren(new);
1726 if(CBgPixel(new) != CBgPixel(current))
1728 XtSetArg(args[n],XmNbackground,CBgPixel(new));n++;
1730 if(CBgPixmap(new) != CBgPixmap(current))
1732 XtSetArg(args[n],XmNbackgroundPixmap,CBgPixmap(new));n++;
1734 if(MFgPixel(new) != MFgPixel(current))
1736 XtSetArg(args[n],XmNforeground,MFgPixel(new));n++;
1739 XtSetValues (Text(new),args,n);
1741 XtSetValues (Label(new),args,n);
1743 XtSetValues (UpArrow(new),args,n);
1745 XtSetValues (DownArrow(new),args,n);
1752 * This function clears the shadow around our widget. If all is TRUE,
1753 * then clear all 4 sides; otherwise, only clear the right and bottom
1754 * sides (during resize).
1757 ClearShadow( DtSpinBoxWidget w,
1760 Dimension shadow = SPIN_SHADOW(w);
1761 Dimension margin_w = SPIN_MARGIN_W(w);
1762 Dimension margin_h = SPIN_MARGIN_H(w);
1764 if ((shadow > 0) && XtIsRealized((Widget)w)) {
1766 XClearArea(XtDisplayOfObject((Widget)w),
1767 XtWindowOfObject((Widget)w),
1769 OldWidth(w) - (margin_w * 2),
1771 XClearArea(XtDisplayOfObject((Widget)w),
1772 XtWindowOfObject((Widget)w),
1773 margin_w, margin_h, shadow,
1774 OldHeight(w) - (margin_h * 2), FALSE);
1776 XClearArea(XtDisplayOfObject((Widget)w), XtWindowOfObject((Widget)w),
1777 margin_w, OldHeight(w) - margin_h - shadow,
1778 OldWidth(w) - (margin_w * 2), shadow, FALSE);
1779 XClearArea(XtDisplayOfObject((Widget)w), XtWindowOfObject((Widget)w),
1780 OldWidth(w) - margin_w - shadow,
1782 OldHeight(w) - (margin_h * 2), FALSE);
1784 DrawHighlight(w, TRUE);
1788 * This functions draws the shadow around our spin_box.
1791 DrawShadow(DtSpinBoxWidget w)
1793 Dimension shadow = SPIN_SHADOW(w);
1794 Dimension margin_w = SPIN_MARGIN_W(w);
1795 Dimension margin_h = SPIN_MARGIN_H(w);
1797 if ((shadow > 0) && XtIsRealized((Widget)w)) {
1798 XmeDrawShadows(XtDisplayOfObject((Widget)w),
1799 XtWindowOfObject((Widget)w),
1800 w->manager.top_shadow_GC,
1801 w->manager.bottom_shadow_GC,
1803 w->core.width - (margin_w * 2),
1804 w->core.height - (margin_h * 2),
1805 shadow, XmSHADOW_OUT);
1807 DrawHighlight(w, FALSE);
1811 * This function sets up the items information for the SpinBox, as
1812 * well as variables needed for child_type.
1815 StoreResourceInfo( DtSpinBoxPart *spin_p,
1816 DtSpinBoxPart *old_p,
1819 XmStringTable table;
1822 if (do_items && spin_p->items) {
1823 /* Free up current items if needed */
1824 if (old_p && old_p->items) {
1825 for (i = 0; i < old_p->item_count; i++) {
1826 XmStringFree(old_p->items[i]);
1828 XtFree((char*)old_p->items);
1832 * Loop through all the items, copy them into our space.
1834 table = (XmStringTable)XtMalloc(sizeof(XmString) * spin_p->item_count);
1835 for (i = 0; i < spin_p->item_count; i++) {
1836 table[i] = XmStringCopy(spin_p->items[i]);
1838 spin_p->items = table;
1839 for (i = 0; i < spin_p->item_count; i++)
1840 spin_p->items[i] = table[i];
1844 * Store the numeric information
1847 /* get base number for convert ints to floats */
1848 for (i = 0; i < spin_p->decimal_points; i++)
1851 /* Set new initial values */
1852 spin_p->min = (float)spin_p->minimum/base;
1853 spin_p->max = (float)spin_p->maximum/base;
1854 spin_p->increment = (float)spin_p->numeric_increment/base;
1856 spin_p->current = (float)spin_p->position/base;
1858 /* Create format string used to build correct XmString value */
1859 spin_p->float_format[0] = '%';
1860 sprintf((char*)(spin_p->float_format+1), ".%df", spin_p->decimal_points);
1864 /* Caller must free string */
1866 GetTextString(XmString xm_string)
1868 XmStringContext context;
1869 XmStringComponentType type;
1870 XmStringCharSet charset;
1871 XmStringDirection direction;
1872 XmStringComponentType unknown_tag;
1876 Boolean done = FALSE;
1878 XmStringInitContext(&context, xm_string);
1880 /* Loop until 1st char* found */
1882 type = XmStringGetNextComponent(context, &text, &charset,
1883 &direction, &unknown_tag,
1886 case XmSTRING_COMPONENT_END:
1889 case XmSTRING_COMPONENT_TEXT:
1890 case XmSTRING_COMPONENT_LOCALE_TEXT:
1897 XmStringFreeContext(context);
1902 * Take the string out of the list and put it into the text-field.
1903 * text-fields don't handle xm-strings, so we must get the char*
1904 * out of it (only getting the first segment). This is slower than
1905 * storing the text-strings (char*) ourselves, but that would take
1906 * up a lot of memory. Since this setting happens during a user
1907 * action, speed isn't a problem.
1910 SetTextFieldData(DtSpinBoxWidget spin)
1912 char string[NUMERIC_LENGTH];
1918 if (ChildType(spin) == DtNUMERIC) {
1919 sprintf(string, FloatFormat(spin), (float)(Current(spin)));
1920 XtSetArg(arg, XmNvalue, string);
1921 XtSetValues(Text(spin), &arg, 1);
1924 if (ItemCount(spin) == 0){
1925 XtSetArg(arg, XmNvalue, "");
1926 XtSetValues(Text(spin), &arg, 1);
1930 xm_string = (Items(spin))[Position(spin)];
1931 if ((text = GetTextString(xm_string))) {
1932 XtSetArg(arg, XmNvalue, text);
1933 XtSetValues(Text(spin), &arg, 1);
1941 * Set the maximum size of the label, depending on the
1942 * characteristics of the list of items. Not very efficient
1943 * if switching from numeric to non-numeric.
1946 SetMaximumLabelSize(DtSpinBoxPart *spin_p)
1949 XmFontList font_list;
1950 char string[NUMERIC_LENGTH];
1951 Dimension width, height;
1952 Dimension longest = 0;
1953 Dimension highest = 0;
1956 /* Resolution Independent */
1957 unsigned char unit_type;
1959 /* Get font info from the widget */
1960 XtSetArg(args[0], XmNfontList, &font_list);
1961 XtSetArg(args[1], XmNunitType, &unit_type); /* resolution Independent */
1962 XtGetValues(spin_p->label, args, 2);
1963 if ( unit_type != XmPIXELS) {
1964 XtSetArg(args[0], XmNunitType, XmPIXELS);
1965 XtSetValues(spin_p->label, args, 1);
1968 if (spin_p->child_type == DtNUMERIC) {
1969 /* Find out maximum size of the widget from min/max */
1970 sprintf(string, spin_p->float_format, spin_p->min);
1971 xm_string = XmStringCreateLocalized(string);
1972 XmStringExtent(font_list, xm_string, &longest, &highest);
1973 XmStringFree(xm_string);
1974 sprintf(string, spin_p->float_format, spin_p->max);
1975 xm_string = XmStringCreateLocalized(string);
1976 XmStringExtent(font_list, xm_string, &width, &height);
1977 XmStringFree(xm_string);
1979 longest = (width > longest) ? width : longest;
1980 highest = (height > highest) ? height : highest;
1982 else if (spin_p->items) {
1984 * Loop through all the items to find the biggest dimensions
1986 for (i = 0; i < spin_p->item_count; i++) {
1987 XmStringExtent(font_list, spin_p->items[i], &width, &height);
1988 longest = (width > longest) ? width : longest;
1989 highest = (height > highest) ? height : highest;
1993 XmStringExtent(font_list, InitLabel, &longest, &highest);
1996 spin_p->label_max_length =
1997 ( (Dimension)(longest + ( (LABEL_PADDING + TEXT_CONTEXT_MARGIN) *2) ) >
1998 (Dimension)Width(spin_p->label) ) ?
1999 (longest + ((LABEL_PADDING+TEXT_CONTEXT_MARGIN) * 2)) :
2000 Width(spin_p->label);
2002 spin_p->label_max_height = highest > Height(spin_p->label) ?
2003 highest : Height(spin_p->label);
2004 XtResizeWidget(spin_p->label, spin_p->label_max_length,
2005 spin_p->label_max_height,
2006 spin_p->label->core.border_width);
2008 /* Resolution Independent */
2009 if ( unit_type != XmPIXELS) {
2010 XtSetArg(args[0], XmNunitType, unit_type);
2011 XtSetValues(spin_p->label, args, 1);
2017 * Put the current list item into the label.
2020 SetLabelData(DtSpinBoxWidget spin)
2023 char string[NUMERIC_LENGTH];
2024 int index = Position(spin);
2027 if (ChildType(spin) == DtNUMERIC) {
2028 sprintf(string, FloatFormat(spin), (float)Current(spin));
2029 xm_string = XmStringCreateLocalized(string);
2030 XtSetArg(arg, XmNlabelString, xm_string);
2031 XtSetValues(Label(spin), &arg, 1);
2035 * If the item is not empty, get the current item from the list, else
2038 xm_string = (ItemCount(spin)>0) ? (Items(spin))[index] : InitLabel;
2039 XtSetArg(arg, XmNlabelString, xm_string);
2040 XtSetValues(Label(spin), &arg, 1);
2045 * Timout dispatch routine. This calls the appropriate callback function
2046 * to simulate up or down arrow activation.
2049 timer_dispatch( XtPointer client_data,
2052 DtSpinBoxWidget spin_w = (DtSpinBoxWidget)client_data;
2054 Timer(spin_w) = (XtIntervalId)NULL;
2055 InitCb(spin_w) = FALSE;
2056 if (WhichArrow(spin_w) == XmARROW_UP) {
2057 if (Grabbed(spin_w)) {
2058 XtRemoveGrab(UpArrow(spin_w));
2059 Grabbed(spin_w) = FALSE;
2061 up_cb(NULL, client_data, NULL);
2064 if (Grabbed(spin_w)) {
2065 XtRemoveGrab(DownArrow(spin_w));
2066 Grabbed(spin_w) = FALSE;
2068 down_cb(NULL, client_data, NULL);
2073 TextFieldActivate(DtSpinBoxPart *spin_p)
2075 XmTextFieldWidget w = (XmTextFieldWidget)(spin_p->text);
2076 XmAnyCallbackStruct cb;
2077 char string[NUMERIC_LENGTH];
2081 Boolean free_me = TRUE;
2083 XtSetArg(arg, XmNvalue, &data);
2084 XtGetValues((Widget)w, &arg, 1);
2086 if (spin_p->child_type == DtNUMERIC) {
2087 sprintf(string, spin_p->float_format, (float)spin_p->current);
2091 else if (spin_p->items)
2092 text = GetTextString(spin_p->items[spin_p->position]);
2094 if (text && data && (strcmp(text, data) == 0)) {
2099 /* Only send callback if both are not NULL */
2100 else if (!((text == NULL) && (data == NULL))) {
2101 cb.reason = XmCR_ACTIVATE;
2104 if (XtHasCallbacks((Widget)w, XmNactivateCallback)==XtCallbackHasSome)
2105 XtCallCallbacks((Widget)w, XmNactivateCallback,
2107 if (text && free_me)
2113 * This function calls the appropriate callback for the spin_box.
2114 * It gathers the correct arguments and fills in the callback structure.
2117 SendCallback( DtSpinBoxWidget spin,
2119 Boolean value_changed,
2121 float current, /* Used for numeric */
2124 DtSpinBoxCallbackStruct cb;
2125 XmString xm_string = NULL;
2126 char string[NUMERIC_LENGTH];
2128 if (ChildType(spin) == DtNUMERIC) {
2129 sprintf(string, FloatFormat(spin), (float)current);
2130 xm_string = XmStringCreateLocalized(string);
2133 xm_string = (ItemCount(spin)>0) ? (Items(spin))[position] : InitLabel;
2134 xm_string = XmStringCopy(xm_string);
2138 cb.reason = DtCR_OK;
2139 else if (WhichArrow(spin) == XmARROW_UP)
2140 cb.reason = DtCR_SPIN_NEXT;
2142 cb.reason = DtCR_SPIN_PRIOR;
2145 cb.widget = (Widget)spin;
2146 cb.position = position;
2147 cb.value = xm_string;
2148 cb.crossed_boundary = crossed;
2149 if (value_changed) {
2150 XtCallCallbackList((Widget)spin, ValueChangedCallback(spin),
2155 XtCallCallbackList((Widget)spin, ModifyVerifyCallback(spin),
2158 XmStringFree(xm_string);
2165 * This function gets called by the up/down arm callback functions.
2166 * We set up the timer and send the modify-verify and value-changed
2168 * There are potential problems if the user does some weird stuff
2169 * in the callbacks. I have added protection against the case where
2170 * a user does a grab (with XtAddGrab/XtPopup/etc.) in the callbacks.
2171 * Grabbing in the callback would cause us to lose the button-release
2172 * (disarm), which would make the timer go on forever. A grab is
2173 * done after the callbacks just to make sure we will receive the
2174 * button-release. The button-release will call disarm_cb() which will
2175 * un-grab and disable the timer. I have also added a leave callback
2176 * which helps to protect against these kinds of problems.
2177 * If the callback goes into another event-loop (which I hope would
2178 * never happen), we would spin continuously (since our XtAddGrab never
2179 * get called), until the user left the window (which would call
2180 * grab_leave_cb). The grabbed flag gets set if we do the grab, so that
2181 * we know if we can remove the grab. Our XtAddGrab() might not get called
2182 * if the callback enters another event-loop.
2184 * The event sent in the callback will be NULL during continuous spinning.
2187 FinishUpDown( DtSpinBoxWidget spin,
2188 XtPointer arrow_call_data,
2193 XmArrowButtonCallbackStruct *arrow_data;
2194 XEvent *last_event = NULL;
2195 int repeat_delay = RepeatDelay(spin);
2198 repeat_delay = InitialDelay(spin);
2199 Timer(spin) = XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)spin),
2200 repeat_delay, timer_dispatch, (XtPointer)spin);
2202 /* Try to get Xevent */
2203 if ((arrow_data = (XmArrowButtonCallbackStruct*)arrow_call_data))
2204 last_event = arrow_data->event;
2207 * Send modify_verify callback. If user says no, then
2208 * clear the timer and reset the state before returning.
2210 if (SendCallback(spin, last_event, FALSE, new_position,
2211 new_current, crossed) == FALSE) {
2212 XtRemoveTimeOut(Timer(spin));
2213 Timer(spin) = (XtIntervalId)NULL;
2214 InitCb(spin) = TRUE;
2218 /* User said yes, so set widget values */
2219 Position(spin) = new_position;
2220 Current(spin) = new_current;
2222 SetTextFieldData(spin);
2226 /* send value_changed callback */
2227 (void)SendCallback(spin, last_event, TRUE, Position(spin),
2228 Current(spin), crossed);
2230 /* See notes at top of function on XtAddGrab usage */
2231 Grabbed(spin) = TRUE;
2232 if (WhichArrow(spin) == XmARROW_UP)
2233 XtAddGrab(UpArrow(spin), FALSE, FALSE);
2235 XtAddGrab(DownArrow(spin), FALSE, FALSE);
2239 * Show the next value in the SpinBox. If numeric, just add the
2240 * increment value. If using string-table, get the next one in the
2241 * table. This function takes care of wrap around. Set the arrow
2242 * type. This is needed for the timer_dispatch function. up_cb
2243 * gets called the first time the button is pressed, and each time the
2245 * All widget internals are expected to be correct here; they
2246 * get verified when set by the user.
2250 XtPointer client_data,
2251 XtPointer call_data)
2253 DtSpinBoxWidget spin = (DtSpinBoxWidget)client_data;
2254 DtSpinBoxPart *spin_p = (DtSpinBoxPart*)
2255 &(XmField(spin,ipot,DtSpinBox,label,Widget));
2256 Boolean crossed_boundary = FALSE;
2257 int new_position = Position(spin);
2258 float new_current = Current(spin);
2261 if ( !_XmFocusIsHere( (Widget)spin) )
2262 XmProcessTraversal((Widget)spin,
2263 (XmTraversalDirection) XmTRAVERSE_CURRENT);
2266 TextFieldActivate(spin_p);
2269 * If non-numeric and no items then ignore the user activate event.
2271 if ((ChildType(spin) == DtSTRING) && (ItemCount(spin) == 0))
2274 if (ChildType(spin) == DtNUMERIC) {
2275 if ((new_current + Increment(spin)) > Max(spin)) {
2277 new_position = Minimum(spin);
2278 new_current = Min(spin);
2279 crossed_boundary = TRUE;
2282 XBell(XtDisplayOfObject((Widget)spin), 0);
2285 new_position += NumericIncrement(spin);
2286 new_current += Increment(spin);
2289 else if (ItemCount(spin) >0) {
2290 if (new_position == (ItemCount(spin) - 1)) {
2293 crossed_boundary = TRUE;
2296 XBell(XtDisplayOfObject((Widget)spin), 0);
2302 WhichArrow(spin) = XmARROW_UP;
2303 FinishUpDown(spin, call_data, new_position, new_current, crossed_boundary);
2308 * Show the previous value in the SpinBox. If numeric, just decrement
2309 * the increment value. If using string-table, get the previous one in the
2310 * table. This function takes care of wrap around. Set the arrow
2311 * type. This is needed for the timer_dispatch function. down_cb
2312 * gets called the first time the button is pressed, and each time the
2314 * All widget internals are expected to be correct here; they
2315 * get verified when set by the user.
2319 XtPointer client_data,
2320 XtPointer call_data)
2322 DtSpinBoxWidget spin = (DtSpinBoxWidget)client_data;
2323 DtSpinBoxPart *spin_p = (DtSpinBoxPart*)
2324 &(XmField(spin,ipot,DtSpinBox,label,Widget));
2325 Boolean crossed_boundary = FALSE;
2326 int new_position = Position(spin);
2327 float new_current = Current(spin);
2329 /* #5: Getting Focus */
2330 if ( !_XmFocusIsHere( (Widget)spin) )
2331 XmProcessTraversal((Widget)spin,
2332 (XmTraversalDirection) XmTRAVERSE_CURRENT);
2335 TextFieldActivate(spin_p);
2338 * If non-numeric and no items then ignore the user activate event.
2340 if ((ChildType(spin) == DtSTRING) && (ItemCount(spin) == 0))
2343 if (ChildType(spin) == DtNUMERIC) {
2344 if ((new_current - Increment(spin)) < Min(spin)) {
2346 new_current = Max(spin);
2347 new_position = Maximum(spin);
2348 crossed_boundary = TRUE;
2351 XBell(XtDisplayOfObject((Widget)spin), 0);
2354 new_current -= Increment(spin);
2355 new_position -= NumericIncrement(spin);
2358 else if (ItemCount(spin)>0) {
2359 if (new_position == 0) {
2361 new_position = ItemCount(spin) - 1;
2362 crossed_boundary = TRUE;
2365 XBell(XtDisplayOfObject((Widget)spin), 0);
2371 WhichArrow(spin) = XmARROW_DOWN;
2372 FinishUpDown(spin, call_data, new_position, new_current, crossed_boundary);
2376 disarm_cb( Widget w,
2377 XtPointer client_data,
2378 XtPointer call_data)
2380 DtSpinBoxWidget spin = (DtSpinBoxWidget)client_data;
2382 if ((int)Timer(spin)) {
2383 InitCb(spin) = TRUE;
2384 XtRemoveTimeOut(Timer(spin));
2385 Timer(spin) = (XtIntervalId)NULL;
2386 if (Grabbed(spin)) {
2388 Grabbed(spin) = FALSE;
2394 grab_leave_cb( Widget w,
2395 XtPointer client_data,
2399 DtSpinBoxWidget spin = (DtSpinBoxWidget)client_data;
2401 if ((int)Timer(spin) &&
2402 ((event->xcrossing.mode == NotifyGrab) ||
2403 (event->xcrossing.mode == NotifyUngrab) ||
2404 (!(event->xcrossing.state & Button1Mask)))) {
2405 InitCb(spin) = TRUE;
2406 XtRemoveTimeOut(Timer(spin));
2407 Timer(spin) = (XtIntervalId)NULL;
2408 if (Grabbed(spin)) {
2410 Grabbed(spin) = FALSE;
2416 * We get the text-field losing-focus callback, so pass it on to
2417 * the user if they requested it. Our losing-focus callback
2418 * is just a convenience callback, so that the user doesn't
2419 * have to get the text-field first. This make our integration
2420 * with XDesigner a little easier.
2423 text_losing_focus_cb( Widget w,
2424 XtPointer client_data,
2425 XtPointer call_data)
2427 DtSpinBoxWidget spin = (DtSpinBoxWidget)client_data;
2429 if (LosingFocusCallback(spin))
2430 XtCallCallbackList((Widget)spin,
2431 LosingFocusCallback(spin),
2432 (XtPointer)call_data);
2436 * We get the text-field activate callback, so pass it on to
2437 * the user if they requested it. Our activate callback
2438 * is just a convenience callback, so that the user doesn't
2439 * have to get the text-field first. This make our integration
2440 * with XDesigner a little easier.
2443 text_activate_cb(Widget w,
2444 XtPointer client_data,
2445 XtPointer call_data)
2447 DtSpinBoxWidget spin = (DtSpinBoxWidget)client_data;
2449 if (ActivateCallback(spin))
2450 XtCallCallbackList((Widget)spin,
2451 ActivateCallback(spin),
2452 (XtPointer)call_data);
2456 * We get the text-field focus callback, so pass it on to
2457 * the user if they requested it. Our focus callback
2458 * is just a convenience callback, so that the user doesn't
2459 * have to get the text-field first. This make our integration
2460 * with XDesigner a little easier.
2463 text_focus_cb( Widget w,
2464 XtPointer client_data,
2465 XtPointer call_data)
2467 DtSpinBoxWidget spin = (DtSpinBoxWidget)client_data;
2469 if (FocusCallback(spin))
2470 XtCallCallbackList((Widget)spin,
2471 FocusCallback(spin),
2472 (XtPointer)call_data);
2477 * Synthetic resource get functions.
2480 static XmImportOperator
2481 _XmSetSyntheticResForChild( Widget widget,
2485 return(XmSYNTHETIC_LOAD);
2489 _DtSpinBoxGetArrowSize( Widget w,
2490 int resource_offset,
2493 DtSpinBoxWidget spin = (DtSpinBoxWidget)w;
2498 XtSetArg(arg, XmNheight, &data);
2499 XtGetValues(UpArrow(spin), &arg, 1);
2500 *value = (XtArgVal)data;
2504 * Routines which manipulate the SpinBox list. These are external
2505 * for use by users of our widget.
2509 DtCreateSpinBox( Widget parent,
2514 return(XtCreateWidget(name, dtSpinBoxWidgetClass, parent,
2515 arglist, num_args));
2519 DtSpinBoxAddItem( Widget spinw,
2523 DtSpinBoxWidget spin = (DtSpinBoxWidget)spinw;
2524 DtSpinBoxPart *spin_p;
2525 XmString old, new_str, tmp;
2527 _DtWidgetToAppContext(spinw);
2530 spin_p = (DtSpinBoxPart*) &(XmField(spin,ipot,DtSpinBox,label,Widget));
2532 total_items = ItemCount(spin) + 1;
2533 Items(spin) = (XmString *)XtRealloc((char*)Items(spin),
2534 (sizeof(XmString) * total_items));
2535 new_str = XmStringCopy(item);
2537 pos--; /* User gives pos starting at 1 (0 means end of list) */
2539 if ((pos < 0) || (pos > ItemCount(spin)))
2540 pos = ItemCount(spin);
2542 if (pos >= ItemCount(spin))
2543 (Items(spin))[pos] = new_str;
2545 old = (Items(spin))[pos];
2546 (Items(spin))[pos] = new_str;
2547 for (pos++; pos < total_items; pos++) {
2548 tmp = (Items(spin))[pos];
2549 (Items(spin))[pos] = old;
2553 ItemCount(spin) = total_items;
2556 SetMaximumLabelSize(spin_p);
2557 if (Editable(spin) == FALSE) {
2558 ClearShadow(spin, TRUE);
2559 if (RecomputeSize(spin))
2560 SetSpinBoxSize(spin);
2561 LayoutChildren(spin);
2566 /* Update the text-field or label */
2568 SetTextFieldData(spin);
2578 DtSpinBoxDeletePos( Widget spinw,
2581 DtSpinBoxWidget spin = (DtSpinBoxWidget)spinw;
2582 DtSpinBoxPart *spin_p;
2584 _DtWidgetToAppContext(spinw);
2587 if (ItemCount(spin) < 1)
2593 spin_p = (DtSpinBoxPart*) &(XmField(spin,ipot,DtSpinBox,label,Widget));
2596 if ((pos < 0) || (pos > ItemCount(spin)))
2597 pos = ItemCount(spin) - 1;
2599 total_items = ItemCount(spin) - 1;
2600 XmStringFree((Items(spin))[pos]);
2602 /* To keep Position of SpinBox up to date */
2603 if (Position(spin) > 0 &&
2604 ((Position(spin) >= total_items) || pos < Position(spin)) )
2605 Position(spin) = Position(spin) - 1;
2607 if (pos < ItemCount(spin)) {
2608 for (; pos < total_items; pos++)
2609 (Items(spin))[pos] = (Items(spin))[pos+1];
2611 if (total_items > 0)
2612 Items(spin) = (XmString *)XtRealloc((char*)Items(spin),
2613 (sizeof(XmString) * total_items));
2615 XtFree((char *)Items(spin));
2616 Items(spin) = (XmString *)NULL;
2618 ItemCount(spin) = total_items;
2621 SetMaximumLabelSize(spin_p);
2622 if (Editable(spin) == FALSE) {
2623 ClearShadow(spin, TRUE);
2624 if (RecomputeSize(spin))
2625 SetSpinBoxSize(spin);
2626 LayoutChildren(spin);
2631 /* Update the text-field or label */
2633 SetTextFieldData(spin);
2641 * Make the given item the currently visible item in the
2642 * text-field or label.
2645 DtSpinBoxSetItem( Widget spinw,
2648 DtSpinBoxWidget spin = (DtSpinBoxWidget)spinw;
2650 _DtWidgetToAppContext(spinw);
2653 if (item && ItemCount(spin)>0) {
2654 for (i = 0; i < ItemCount(spin); i++)
2655 if (XmStringCompare(item, (Items(spin))[i]))
2657 if (i < ItemCount(spin)) {
2660 SetTextFieldData(spin);
2665 XtWarning(SB_SET_ITEM);
2668 XtWarning(SB_SET_ITEM);