1 /***********************************************************************/
2 /* Open Visualization Data Explorer                                    */
3 /* (C) Copyright IBM Corp. 1989,1999                                   */
4 /* ALL RIGHTS RESERVED                                                 */
5 /* This code licensed under the                                        */
6 /*    "IBM PUBLIC LICENSE - Open Visualization Data Explorer"          */
7 /***********************************************************************/
8 
9 #include <dxconfig.h>
10 #include "../base/defines.h"
11 
12 
13 
14 /* Stepper resize logic:
15 
16 	1. Default - XmNrecomputeSize = TRUE;  This means that the stepper
17 	   widget will automatically resize itself based on the min and max
18 	   values of the widget, and the number of decimal places.  This was
19 	   done to prevent frequent resizes of steppers in the slider widget.
20 
21 	2. XmNrecomputeSize = FALSE;  In this case, the widget sizes itself
22 	   based on the XmNdigits resource.  This delimits the total size
23 	   of the widget.  This mode presents potentially unsightly operation
24 	   of the widget if the size in not adequate to handle the min/max
25 	   values of the widget
26 */
27 
28 #ifdef OS2
29 #include <stdlib.h>
30 #include <types.h>
31 #endif
32 
33 #include <X11/StringDefs.h>
34 #include <X11/IntrinsicP.h>
35 #include <X11/Intrinsic.h>
36 #include <X11/CoreP.h>
37 #include <X11/CompositeP.h>
38 #include <X11/Composite.h>
39 #include <X11/Constraint.h>
40 #include <Xm/XmP.h>
41 #include <Xm/Xm.h>
42 #include <Xm/BulletinB.h>
43 #include <Xm/ArrowB.h>
44 #include <limits.h>
45 #include <math.h>
46 #include <float.h>
47 #include "Number.h"
48 #include "StepperP.h"
49 #include "Stepper.h"
50 #include "gamma.h"
51 #include "findcolor.h"
52 
53 #if !defined(HAVE_TRUNC)
54 #define trunc(c)        ((double)((int)(c)))
55 #endif
56 
57 
58 /*
59  *  Error messages:
60  */
61 #define MESSAGE1	"The Maximum value must be greater than the Minimum."
62 #define MESSAGE2	"Meter value exceeds the Maximum value."
63 #define MESSAGE3	"Meter value is less then the Minimum value."
64 #define MESSAGE4	"The step value will be rounded.  Check decimal places."
65 
66 /*  A locally used constant  */
67 #define XmCR_REPEAT_ARM 11522
68 
69 /*  Define struct for commonly used group of dimension and coordinate values  */
70 struct layout {
71     int number_x, number_y;
72     Dimension number_width, number_height;
73     int up_left_x, up_left_y;
74     int down_right_x, down_right_y;
75     Dimension arrow_width, arrow_height;
76     Dimension field_width, field_height;
77 };
78 
79 
80 /* External Functions */
81 void SyncMultitypeData( MultitypeData* new, short type ); /* from Number.c */
82 
83 
84 /*
85  *  Forward local subroutine and function declarations:
86  */
87 static void	ClassInitialize	    ();
88 static void	Initialize	    (XmStepperWidget		request,
89 				     XmStepperWidget		new);
90 static Boolean	SetValues	    (XmStepperWidget		current,
91 				     XmStepperWidget		request,
92 				     XmStepperWidget		new);
93 static void	Destroy		    (XmStepperWidget		sw);
94 static void	Resize		    (XmStepperWidget		sw);
95 static void	ChangeManaged	    (XmStepperWidget		sw);
96 static void	Redisplay	    (XmStepperWidget		sw,
97 				     XEvent *			event,
98 				     Region			region);
99 static void	Arm		    (XmStepperWidget		sw,
100 				     XButtonPressedEvent *	event);
101 static void	Activate	    (XmStepperWidget		sw,
102 				     XButtonPressedEvent *	event);
103 static void	CallFromNumber	    (Widget			w,
104 				     XmStepperWidget		sw,
105 				     XmDoubleCallbackStruct *	call_data);
106 static void	CallbackActivate    (XmStepperWidget		sw);
107 static void	CallbackStep	    (XmStepperWidget		sw,
108 				     Boolean			increase);
109 static void	VerifyValueRange    (XmStepperWidget		sw, Boolean);
110 static void	ComputeLayout	    (XmStepperWidget		sw,
111 				     struct layout *		loc);
112 static void	LayoutStepper	    (XmStepperWidget		sw);
113 static Boolean	IncrementStepper    (XmStepperWidget		sw,
114 				     Boolean			increase,
115 				     double			step_size);
116 static void	ButtonIncrease	    (Widget			w,
117 				     XmStepperWidget		sw,
118 				     XmAnyCallbackStruct *	call_data);
119 static void	ButtonDecrease	    (Widget			w,
120 				     XmStepperWidget		sw,
121 				     XmAnyCallbackStruct *	call_data);
122 static void	ButtonIsReleased    (Widget			w,
123 				     XmStepperWidget		sw,
124 				     XmAnyCallbackStruct *	call_data);
125 static Boolean	ButtonArmEvent      (Widget			w,
126 				     XmStepperWidget		sw,
127 				     XtCallbackProc		callback_proc);
128 static void	RepeatDigitButton   (XmStepperWidget		sw,
129 				     XtIntervalId *		id);
130 static XtGeometryResult
131 PreferredSize (XmStepperWidget , XtWidgetGeometry *, XtWidgetGeometry *);
132 static XtGeometryResult
133                 GeometryManager         (Widget w,
134                                          XtWidgetGeometry *request,
135                                          XtWidgetGeometry *reply);
136 
137 static void 	WarningCallback	    ( Widget w, XmStepperWidget sw,
138 				     XmNumberWarningCallbackStruct *call_data );
139 static
140 Boolean	UpdateMultitypeData (XmStepperWidget sw, MultitypeData* new,
141 		MultitypeData* current);
142 
143 
144 /*  Default translation table and action list  */
145 static char defaultTranslations[] =
146     "<Btn1Down>:     Arm()\n\
147      <Btn1Up>:	     Activate()";
148 /*
149     "<Btn1Down>:     Arm()\n\
150      <Btn1Up>:	     Activate()\n\
151      <EnterWindow>:  Enter() \n\
152      <FocusIn>:      FocusIn()";
153  */
154 
155 static XtActionsRec actionsList[] =
156 {
157    { "Arm",      (XtActionProc) Arm  },
158    { "Activate", (XtActionProc) Activate },
159 };
160 /*
161    { "Arm",      (XtActionProc) Arm  },
162    { "Activate", (XtActionProc) Activate },
163    { "Enter",    (XtActionProc) _XmManagerEnter },
164    { "FocusIn",  (XtActionProc) _XmManagerFocusIn },
165 };
166  */
167 
168 
169 /*
170  *  Resource definitions for Stepper class:
171  */
172 
173 /*  Declare defaults that can be assigned through pointers  */
174 #if defined(aviion)
175 /* FLT_MAX is not a constant, but an external variable.  these must be
176  *  initialized at run time instead on the data general.
177  */
178 static int DefaultInitialized = FALSE;
179 #define DOUBLE_MIN  0.0
180 #define DOUBLE_MAX  0.0
181 #define FLOAT_MIN   0.0
182 #define FLOAT_MAX   0.0
183 #else
184 #define DOUBLE_MIN -FLT_MAX
185 #define DOUBLE_MAX  FLT_MAX
186 #define FLOAT_MIN  -FLT_MAX
187 #define FLOAT_MAX   FLT_MAX
188 #endif
189 
190 #define DEF_MIN FLOAT_MIN
191 #define DEF_MAX FLOAT_MAX
192 #define DEF_VALUE 0
193 #define DEF_STEP 1
194 
195 #if defined(hp700) || defined(solaris) || defined(sun4) || defined(aviion) || defined (intelnt) || defined(OS2)
196 #   define trunc(x) ((double)((int)(x)))
197 #endif
198 
199 static double DefaultMinDbl = (double)DEF_MIN;
200 static double DefaultMaxDbl = (double)DEF_MAX;
201 static double DefaultValDbl = (double)DEF_VALUE;
202 static double DefaultStepDbl = (double)DEF_STEP;
203 static float DefaultMinFlt = (float)FLOAT_MIN;
204 static float DefaultMaxFlt = (float)FLOAT_MAX;
205 static float DefaultValFlt = (float)DEF_VALUE;
206 static float DefaultStepFlt = (float)DEF_STEP;
207 
208 static XtResource resources[] =
209 {
210     {
211       XmNdataType, XmCDataType, XmRShort, sizeof(short),
212       XtOffset(XmStepperWidget, stepper.data_type),
213       XmRImmediate, (XtPointer) INTEGER
214     },
215     {
216       XmNdValue, XmCDValue, XmRDouble, sizeof(double),
217       XtOffset(XmStepperWidget, stepper.value.d),
218       XmRDouble, (XtPointer) &DefaultValDbl
219     },
220     {
221       XmNfValue, XmCFValue, XmRFloat, sizeof(float),
222       XtOffset(XmStepperWidget, stepper.value.f),
223       XmRFloat, (XtPointer) &DefaultValFlt
224     },
225     {
226       XmNiValue, XmCIValue, XmRInt, sizeof(int),
227       XtOffset(XmStepperWidget, stepper.value.i),
228       XmRImmediate, (XtPointer) DEF_VALUE
229     },
230     {
231       XmNdMinimum, XmCDMinimum, XmRDouble, sizeof(double),
232       XtOffset(XmStepperWidget, stepper.value_minimum.d),
233       XmRDouble, (XtPointer) &DefaultMinDbl
234     },
235     {
236       XmNfMinimum, XmCFMinimum, XmRFloat, sizeof(float),
237       XtOffset(XmStepperWidget, stepper.value_minimum.f),
238       XmRFloat, (XtPointer) &DefaultMinFlt
239     },
240     {
241       XmNiMinimum, XmCIMinimum, XmRInt, sizeof(int),
242       XtOffset(XmStepperWidget, stepper.value_minimum.i),
243       XmRImmediate, (XtPointer) -1000000
244     },
245     {
246       XmNdMaximum, XmCDMaximum, XmRDouble, sizeof(double),
247       XtOffset(XmStepperWidget, stepper.value_maximum.d),
248       XmRDouble, (XtPointer) &DefaultMaxDbl
249     },
250     {
251       XmNfMaximum, XmCFMaximum, XmRFloat, sizeof(float),
252       XtOffset(XmStepperWidget, stepper.value_maximum.f),
253       XmRFloat, (XtPointer) &DefaultMaxFlt
254     },
255     {
256       XmNiMaximum, XmCIMaximum, XmRInt, sizeof(int),
257       XtOffset(XmStepperWidget, stepper.value_maximum.i),
258       XmRImmediate, (XtPointer) 1000000
259     },
260     {
261       XmNdValueStep, XmCDValueStep, XmRDouble, sizeof(double),
262       XtOffset(XmStepperWidget, stepper.value_step.d),
263       XmRDouble, (XtPointer) &DefaultStepDbl
264     },
265     {
266       XmNfValueStep, XmCFValueStep, XmRFloat, sizeof(float),
267       XtOffset(XmStepperWidget, stepper.value_step.f),
268       XmRFloat, (XtPointer) &DefaultStepFlt
269     },
270     {
271       XmNiValueStep, XmCIValueStep, XmRInt, sizeof(int),
272       XtOffset(XmStepperWidget, stepper.value_step.i),
273       XmRImmediate, (XtPointer) 1
274     },
275     {
276       XmNdigits, XmCDigits, XmRCardinal, sizeof(Cardinal),
277       XtOffset(XmStepperWidget, stepper.num_digits),
278       XmRImmediate, (XtPointer) 8
279     },
280     {
281       XmNdecimalPlaces, XmCDecimalPlaces, XmRInt, sizeof(int),
282       XtOffset(XmStepperWidget, stepper.decimal_places),
283       XmRImmediate, (XtPointer) 0
284     },
285     {
286       XmNtime, XmCTime, XmRCardinal, sizeof(Cardinal),
287       XtOffset(XmStepperWidget, stepper.time_interval),
288       XmRImmediate, (XtPointer) 200
289     },
290     {
291       XmNtimeDelta, XmCTimeDelta, XmRCardinal, sizeof(Cardinal),
292       XtOffset(XmStepperWidget, stepper.time_ddelta),
293       XmRImmediate, (XtPointer) 8
294     },
295     {
296       XmNarmCallback, XmCArmCallback, XmRCallback, sizeof(XtPointer),
297       XtOffset(XmStepperWidget, stepper.step_callback),
298       XmRCallback, NULL
299     },
300     {
301       XmNactivateCallback, XmCActivateCallback, XmRCallback, sizeof(XtPointer),
302       XtOffset(XmStepperWidget, stepper.activate_callback),
303       XmRCallback, NULL
304     },
305     {
306       XmNincreaseDirection, XmCIncreaseDirection, XmRArrowDirection,
307       sizeof(unsigned char),
308       XtOffset(XmStepperWidget, stepper.increase_direction),
309       XmRImmediate, (XtPointer) XmARROW_RIGHT
310     },
311     {
312       XmNcenter, XmCCenter, XmRBoolean, sizeof(Boolean),
313       XtOffset(XmStepperWidget, stepper.center_text),
314       XmRImmediate, (XtPointer) TRUE
315     },
316     {
317       XmNeditable, XmCEditable, XmRBoolean, sizeof(Boolean),
318       XtOffset(XmStepperWidget, stepper.editable),
319       XmRImmediate, (XtPointer) TRUE
320     },
321     {
322       XmNrollOver, XmCRollOver, XmRBoolean, sizeof(Boolean),
323       XtOffset(XmStepperWidget, stepper.roll_over),
324       XmRImmediate, (XtPointer) FALSE
325     },
326     {
327       XmNrecomputeSize, XmCRecomputeSize, XmRBoolean, sizeof(Boolean),
328       XtOffset(XmStepperWidget, stepper.resize_to_number),
329       XmRImmediate, (XtPointer) TRUE
330     },
331     {
332       XmNfixedNotation, XmCFixedNotation, XmRBoolean, sizeof(Boolean),
333       XtOffset(XmStepperWidget, stepper.is_fixed),
334       XmRImmediate, (XtPointer) TRUE
335     },
336     {
337       XmNwarningCallback, XmCCallback, XmRCallback, sizeof(XtPointer),
338       XtOffset(XmStepperWidget, stepper.warning_callback),
339       XmRCallback, NULL
340     },
341     {
342       XmNalignment, XmCAlignment, XmRAlignment, sizeof(unsigned char),
343       XtOffset(XmStepperWidget, stepper.alignment),
344       XmRImmediate, XmALIGNMENT_BEGINNING
345     },
346 };
347 
348 
349 /*
350  *  Stepper class record definition:
351  */
352 XmStepperClassRec xmStepperClassRec = {
353     /*
354      *  CoreClassPart:
355      */
356     {
357 	(WidgetClass)&xmManagerClassRec, /* superclass			*/
358 	"XmStepper",			/* class_name			*/
359 	sizeof(XmStepperRec),		/* widget_size			*/
360 	(XtProc) ClassInitialize,	/* class_initialize		*/
361 	(XtWidgetClassProc) NULL,	/* class_part_initialize	*/
362 	FALSE,				/* class_inited			*/
363 	(XtInitProc) Initialize,	/* initialize			*/
364 	(XtArgsProc) NULL,		/* initialize_hook		*/
365 	(XtRealizeProc)_XtInherit,	/* realize			*/
366 	actionsList,			/* actions			*/
367 	XtNumber(actionsList),		/* num_actions			*/
368 	resources,			/* resources			*/
369 	XtNumber(resources),		/* num_resources		*/
370 	NULLQUARK,			/* xrm_class			*/
371 	FALSE,				/* compress_motion		*/
372 	FALSE,				/* compress_exposure		*/
373 	TRUE,				/* compress_enterleave		*/
374 	FALSE,				/* visible_interest		*/
375 	(XtWidgetProc)Destroy,		/* destroy			*/
376 	(XtWidgetProc)Resize,		/* resize			*/
377 	(XtExposeProc)Redisplay,	/* expose			*/
378 	(XtSetValuesFunc)SetValues,	/* set_values			*/
379 	(XtArgsFunc) NULL,		/* set_values_hook		*/
380 	XtInheritSetValuesAlmost,	/* set_values_almost		*/
381 	(XtArgsProc) NULL,		/* get_values_hook		*/
382 	XtInheritAcceptFocus,		/* accept_focus			*/
383 	XtVersion,			/* version			*/
384 	NULL,				/* callback private		*/
385 	defaultTranslations,		/* tm_table			*/
386 	(XtGeometryHandler)PreferredSize,/* query_geometry		*/
387 	(XtStringProc) NULL,		/* display_accelerator		*/
388 	(void *) NULL,			/* extension			*/
389     },
390     /*
391      *  CompositeClassPart:
392      */
393     {
394 	GeometryManager,		/* geometry_manager		*/
395 	(XtWidgetProc)ChangeManaged,	/* change_managed		*/
396 	(XtWidgetProc)XtInheritInsertChild,	/* insert_child		*/
397 	(XtWidgetProc)XtInheritDeleteChild,	/* delete_child		*/
398 	(void *) NULL,			/* extension			*/
399     },
400     /*
401      *  ConstraintClassPart:
402      */
403     {
404 	NULL,				/* resource list		*/
405 	0,				/* num resources		*/
406 	0,				/* constraint size		*/
407 	NULL,				/* init proc			*/
408 	NULL,				/* destroy proc			*/
409 	NULL,				/* set values proc		*/
410 	NULL,				/* extension			*/
411     },
412     /*
413      *  XmManagerClassPart:
414      */
415     {
416 #if (XmVersion >= 1001)
417       XtInheritTranslations,     		/* translations           */
418 #else
419       (XtTranslations)_XtInherit,     		/* translations           */
420 #endif
421 	NULL,				/* get resources		*/
422 	0,				/* num get_resources		*/
423 	NULL,				/* get_cont_resources		*/
424 	0,				/* num_get_cont_resources	*/
425 	(XmParentProcessProc)NULL,      /* parent_process         */
426 	NULL,				/* extension			*/
427     },
428     /*
429      *  XmStepperClassPart:
430      */
431     {
432 	10,				/* minimum_time_interval	*/
433 	180,				/* initial_time_interval	*/
434   	NULL,				/* font				*/
435   	NULL,
436     }
437 };
438 
439 WidgetClass xmStepperWidgetClass = (WidgetClass)&xmStepperClassRec;
440 
441 
442 /*  Subroutine:	ClassInitialize
443  *  Purpose:	Install non-standard type converters needed by this widget class
444  */
ClassInitialize()445 static void ClassInitialize()
446 {
447 #if defined(aviion)
448     if (!DefaultInitialized) {
449 	DefaultMinDbl = (double)-FLT_MAX;
450 	DefaultMaxDbl = (double)FLT_MAX;
451 	DefaultMinFlt = (float)-FLT_MAX;
452 	DefaultMaxFlt = (float)FLT_MAX;
453 	DefaultInitialized = FALSE;
454     }
455 #endif
456 
457     /*  Install converters for type XmRDouble, XmRFloat  */
458     XmAddFloatConverters();
459 }
460 
461 static XtGeometryResult
PreferredSize(XmStepperWidget step,XtWidgetGeometry * prop,XtWidgetGeometry * resp)462 PreferredSize (XmStepperWidget step, XtWidgetGeometry *prop, XtWidgetGeometry *resp)
463 {
464 struct layout needs;
465 
466     ComputeLayout (step, &needs);
467     memcpy (prop, resp, sizeof(XtWidgetGeometry));
468 
469     /* this is the minimum required */
470     resp->height = needs.field_height;
471     resp->width = needs.field_width;
472     resp->request_mode = CWWidth|CWHeight;
473 
474     if (prop->request_mode & CWHeight) {
475 	if (prop->height == resp->height) return XtGeometryYes;
476 
477     } else if ((resp->width == prop->width) && (resp->height == prop->height)) {
478 	return XtGeometryNo;
479     } else
480 	return XtGeometryAlmost;
481 
482     return XtGeometryNo;
483 }
484 
485 
486 /*  Subroutine:	Initialize
487  *  Effect:	Create and initialize the component widgets
488  */
Initialize(XmStepperWidget request,XmStepperWidget new)489 static void Initialize( XmStepperWidget request, XmStepperWidget new )
490 {
491     Arg wargs[25];
492     struct layout loc;
493     XColor fg_cell_def, bg_cell_def;
494 
495     /*  Check value and limits for consistency and adjust if nescessary  */
496     SyncMultitypeData(&new->stepper.value, new->stepper.data_type);
497     SyncMultitypeData(&new->stepper.value_minimum, new->stepper.data_type);
498     SyncMultitypeData(&new->stepper.value_maximum, new->stepper.data_type);
499     SyncMultitypeData(&new->stepper.value_step, new->stepper.data_type);
500     VerifyValueRange(new, False);
501     (void)UpdateMultitypeData(new, &new->stepper.value_minimum,
502 				 &request->stepper.value_minimum);
503     (void)UpdateMultitypeData(new, &new->stepper.value,
504 				 &request->stepper.value);
505     (void)UpdateMultitypeData(new, &new->stepper.value_maximum,
506 				 &request->stepper.value_maximum);
507     (void)UpdateMultitypeData(new, &new->stepper.value_step,
508 				 &request->stepper.value_step);
509 
510     /*
511      *  Create the panel-meter like number display
512      */
513     XtSetArg(wargs[0], XmNx, 0);
514     XtSetArg(wargs[1], XmNy, 0);
515     /*  Estimate a comfortably large size to initially create NumberWidget  */
516     if(   (new->stepper.increase_direction == XmARROW_LEFT)
517        || (new->stepper.increase_direction == XmARROW_RIGHT) )
518     {
519 	if( (new->core.height <= 0) || (new->core.height > 4096) )
520 	    loc.number_height = 19;
521 	else
522 	    loc.number_height = new->core.height;
523 	if( (new->core.width <= 0) || (new->core.width > 4096) )
524 	    loc.number_width = (new->stepper.num_digits * 6) + 4;
525 	else
526 	    loc.number_width = new->core.width - ((2 * loc.number_height) + 2);
527     }
528     else
529     {
530 	if( new->core.height <= 0 )
531 	    loc.number_height = 19;
532 	else
533 	    loc.number_height = new->core.height / 3;
534 	if( new->core.width <= 0 )
535 	    loc.number_width = (new->stepper.num_digits * 6) + 4;
536 	else
537 	    loc.number_width = new->core.width;
538     }
539     XtSetArg(wargs[2], XmNheight, loc.number_height);
540     XtSetArg(wargs[3], XmNwidth, loc.number_width);
541     XtSetArg(wargs[4], XtNinsertPosition, 0);
542     DoubleSetArg(wargs[5], XmNdMinimum, new->stepper.value_minimum.d);
543     DoubleSetArg(wargs[6], XmNdMaximum, new->stepper.value_maximum.d);
544     DoubleSetArg(wargs[7], XmNdValue, new->stepper.value.d);
545     if( new->stepper.decimal_places == 0 )
546 	XtSetArg(wargs[8], XmNcharPlaces, new->stepper.num_digits);
547     else
548 	XtSetArg(wargs[8], XmNcharPlaces, new->stepper.num_digits + 1);
549     XtSetArg(wargs[9], XmNdecimalPlaces, new->stepper.decimal_places);
550     XtSetArg(wargs[10], XmNcenter, new->stepper.center_text);
551     XtSetArg(wargs[11], XmNeditable, new->stepper.editable);
552     XtSetArg(wargs[12], XmNdataType, DOUBLE);
553     XtSetArg(wargs[13], XmNrecomputeSize, new->stepper.resize_to_number);
554     XtSetArg(wargs[14], XmNfixedNotation, new->stepper.is_fixed);
555     new->stepper.child[0] = XmCreateNumber((Widget)new, "label", wargs, 15);
556     XtAddCallback(new->stepper.child[0],XmNwarningCallback,(XtCallbackProc)WarningCallback,new);
557 
558     /*  Now that the number exists, Calculate the geometries  */
559     ComputeLayout(new, &loc);
560     new->core.width = loc.field_width;
561     new->core.height = loc.field_height;
562 
563     /*  Now reconfigure the number widget correctly  */
564     XtSetArg(wargs[0], XmNx, loc.number_x);
565     XtSetArg(wargs[1], XmNy, loc.number_y);
566     XtSetArg(wargs[2], XmNwidth, loc.number_width);
567     XtSetArg(wargs[3], XmNheight, loc.number_height);
568     XtSetValues(new->stepper.child[0], wargs, 4);
569 
570     /*  Create the upper or left arrow  */
571     XtSetArg(wargs[0], XmNx, loc.up_left_x);
572     XtSetArg(wargs[1], XmNy, loc.up_left_x);
573     XtSetArg(wargs[2], XmNwidth, loc.arrow_width);
574     XtSetArg(wargs[3], XmNheight, loc.arrow_height);
575     if( (new->stepper.increase_direction == XmARROW_LEFT)
576        || (new->stepper.increase_direction == XmARROW_RIGHT) )
577 	XtSetArg(wargs[4], XmNarrowDirection, XmARROW_LEFT);
578     else
579 	XtSetArg(wargs[4], XmNarrowDirection, XmARROW_UP);
580     XtSetArg(wargs[5], XtNinsertPosition, 1);
581     XtSetArg(wargs[6], XmNshadowThickness, new->manager.shadow_thickness);
582     new->stepper.child[1] = XmCreateArrowButton((Widget)new, "left", wargs, 7);
583 
584     /*
585      *  Create the lower or right arrow
586      */
587     XtSetArg(wargs[0], XmNx, loc.down_right_x);
588     XtSetArg(wargs[1], XmNy, loc.down_right_y);
589     if( (new->stepper.increase_direction == XmARROW_LEFT)
590        || (new->stepper.increase_direction == XmARROW_RIGHT) )
591 	XtSetArg(wargs[4], XmNarrowDirection, XmARROW_RIGHT);
592     else
593 	XtSetArg(wargs[4], XmNarrowDirection, XmARROW_DOWN);
594     XtSetArg(wargs[5], XtNinsertPosition, 2);
595     new->stepper.child[2] = XmCreateArrowButton((Widget)new, "right", wargs, 7);
596 
597     /*
598      *  Get the foreground and background colors, and use the average
599      *  for the insensitive color
600      */
601     fg_cell_def.flags = DoRed | DoGreen | DoBlue;
602     bg_cell_def.flags = DoRed | DoGreen | DoBlue;
603     fg_cell_def.pixel = new->manager.foreground;
604     XQueryColor(XtDisplay(new),
605 		DefaultColormapOfScreen(XtScreen(new)),
606 		&fg_cell_def);
607 
608     bg_cell_def.pixel = new->core.background_pixel;
609     XQueryColor(XtDisplay(new),
610                 DefaultColormapOfScreen(XtScreen(new)),
611                 &bg_cell_def);
612     fg_cell_def.red   = fg_cell_def.red/2   + bg_cell_def.red/2;
613     fg_cell_def.green = fg_cell_def.green/2 + bg_cell_def.green/2;
614     fg_cell_def.blue  = fg_cell_def.blue/2  + bg_cell_def.blue/2;
615 
616     /*
617      * Fudge factor to offset the gamma correction
618      */
619     fg_cell_def.red = fg_cell_def.red/2;
620     fg_cell_def.green = fg_cell_def.green/2;
621     fg_cell_def.blue = fg_cell_def.blue/2;
622     gamma_correct(&fg_cell_def);
623     if(!XAllocColor(XtDisplay(new),
624                 DefaultColormapOfScreen(XtScreen(new)),
625 		&fg_cell_def))
626 	{
627 	find_color((Widget)new, &fg_cell_def);
628 	}
629     new->stepper.insens_foreground = fg_cell_def.pixel;
630     if (!(new->core.sensitive && new->core.ancestor_sensitive))
631     {
632 	XtSetArg(wargs[0], XmNforeground, new->stepper.insens_foreground);
633 	XtSetValues(new->stepper.child[1], wargs, 1);
634 	XtSetValues(new->stepper.child[2], wargs, 1);
635     }
636 
637     if( (new->stepper.increase_direction == XmARROW_DOWN)
638        || (new->stepper.increase_direction == XmARROW_RIGHT) )
639     {
640 	XtAddCallback(new->stepper.child[2],XmNarmCallback,(XtCallbackProc)ButtonIncrease, new);
641 	XtAddCallback(new->stepper.child[1],XmNarmCallback,(XtCallbackProc)ButtonDecrease, new);
642     }
643     else
644     {
645 	XtAddCallback(new->stepper.child[1],XmNarmCallback,(XtCallbackProc)ButtonIncrease, new);
646 	XtAddCallback(new->stepper.child[2],XmNarmCallback,(XtCallbackProc)ButtonDecrease, new);
647     }
648     XtAddCallback(new->stepper.child[1],XmNdisarmCallback,(XtCallbackProc)ButtonIsReleased,new);
649     XtAddCallback(new->stepper.child[2],XmNdisarmCallback,(XtCallbackProc)ButtonIsReleased,new);
650     XtAddCallback(new->stepper.child[0],XmNactivateCallback,(XtCallbackProc)CallFromNumber,new);
651     XtAddCallback(new->stepper.child[0],XmNarmCallback,(XtCallbackProc)CallFromNumber, new);
652     XtAddCallback(new->stepper.child[0],XmNdisarmCallback,(XtCallbackProc)CallFromNumber, new);
653 
654     new->stepper.allow_input = TRUE;
655     new->stepper.timer = (XtIntervalId)NULL;
656     XtManageChildren(new->stepper.child, 3);
657 }
658 
659 /*  Subroutine: XtGeometryManager
660  *  Purpose:    Get informed of a request to change a child widget's geometry.
661  */
GeometryManager(Widget w,XtWidgetGeometry * request,XtWidgetGeometry * reply)662 static XtGeometryResult GeometryManager( Widget w, XtWidgetGeometry *request,
663                                          XtWidgetGeometry *reply )
664 {
665 Dimension ret_w, ret_h, new_width, new_height;
666 Widget stepper;
667 Dimension child_width, child_height;
668 XmNumberWidget nw;
669 
670     nw = (XmNumberWidget)w;
671     if (request->request_mode & CWWidth)
672 	{
673 	child_width = request->width;
674 	}
675     else
676 	{
677 	child_width = nw->core.width;
678 	}
679     if (request->request_mode & CWHeight)
680 	{
681 	child_height = request->height;
682 	}
683     else
684 	{
685 	child_height = nw->core.height;
686 	}
687     if ((request->width != w->core.width) ||
688 	(request->height != w->core.height))
689 	{
690 	stepper = XtParent(w);
691 	new_width = stepper->core.width;
692 	if (request->request_mode & CWWidth)
693 	    {
694 	    new_width += (request->width - w->core.width);
695 	    }
696 	new_height = stepper->core.height;
697 	if (request->request_mode & CWHeight)
698 	    {
699 	    new_height += (request->height - w->core.height);
700 	    }
701 	if (XtMakeResizeRequest(stepper, new_width, new_height,
702 				&ret_w, &ret_h) == XtGeometryYes)
703 	    {
704 	    XtResizeWidget(w, child_width, child_height, 0);
705 	    return XtGeometryYes;
706 	    }
707 	else
708 	    {
709 	    return XtGeometryNo;
710 	    }
711 	}
712     return XtGeometryYes;
713 }
714 
715 /*  Subroutine:	SetValues
716  *  Effect:	Handles requests to change things from the application
717  */
SetValues(XmStepperWidget current,XmStepperWidget request,XmStepperWidget new)718 static Boolean SetValues( XmStepperWidget current,
719 			  XmStepperWidget request,
720 			  XmStepperWidget new )
721 {
722     Arg wargs[6];
723     int i;
724     struct layout loc;
725     Boolean need_new_width;
726     Boolean need_new_height;
727 
728     /*
729      * set these to true based on a new resource setting we'll honor which
730      * results in a need for more pixels.  This really ought to include new
731      * font.
732      */
733     need_new_width = need_new_height = False;
734 
735     if( (new->core.sensitive != current->core.sensitive) ||
736         (new->core.ancestor_sensitive != current->core.ancestor_sensitive) )
737     {
738 	if ((new->core.sensitive && new->core.ancestor_sensitive))
739 	{
740 	    XtSetArg(wargs[0], XmNforeground, new->manager.foreground);
741 	    XtSetValues(new->stepper.child[1], wargs, 1);
742 	    XtSetValues(new->stepper.child[2], wargs, 1);
743 	}
744 	else
745 	{
746 	    XtSetArg(wargs[0], XmNforeground, new->stepper.insens_foreground);
747 	    XtSetValues(new->stepper.child[1], wargs, 1);
748 	    XtSetValues(new->stepper.child[2], wargs, 1);
749 	}
750     }
751 
752     SyncMultitypeData(&new->stepper.value, new->stepper.data_type);
753     SyncMultitypeData(&new->stepper.value_minimum, new->stepper.data_type);
754     SyncMultitypeData(&new->stepper.value_maximum, new->stepper.data_type);
755     SyncMultitypeData(&new->stepper.value_step, new->stepper.data_type);
756     VerifyValueRange(new, new->stepper.value_step.d != current->stepper.value_step.d);
757     i = 0;
758     if(   (new->stepper.decimal_places != current->stepper.decimal_places)
759        || (new->stepper.num_digits != current->stepper.num_digits) )
760     {
761 	need_new_width = True;
762 	if( new->stepper.decimal_places == 0 )
763 	    XtSetArg(wargs[i], XmNcharPlaces, new->stepper.num_digits);
764 	else
765 	    XtSetArg(wargs[i], XmNcharPlaces, new->stepper.num_digits + 1);
766 	i++;
767 	XtSetArg(wargs[i], XmNdecimalPlaces, new->stepper.decimal_places);
768 	i++;
769 	DoubleSetArg(wargs[i], XmNdValue, new->stepper.value.d);
770 	i++;
771     }
772     if( UpdateMultitypeData(new, &new->stepper.value_minimum,
773 				 &current->stepper.value_minimum) )
774     {
775 	DoubleSetArg(wargs[i], XmNdMinimum, new->stepper.value_minimum.d);
776 	i++;
777     }
778     if( UpdateMultitypeData(new, &new->stepper.value_maximum,
779 				 &current->stepper.value_maximum) )
780     {
781 	DoubleSetArg(wargs[i], XmNdMaximum, new->stepper.value_maximum.d);
782 	i++;
783     }
784     /*  Finally, check if just the contents have changed  */
785     if( UpdateMultitypeData(new, &new->stepper.value, &current->stepper.value) )
786     {
787 	/*  If we must set values anyway, include this one  */
788 	if( i > 0 )
789 	{
790 	    DoubleSetArg(wargs[i], XmNdValue, new->stepper.value.d);
791 	    i++;
792 	}
793 	/*  If value is only thing to pass, do it more efficiently  */
794 	else if( new->composite.children[0] )
795 	    XmChangeNumberValue((XmNumberWidget)new->composite.children[0],
796 				 new->stepper.value.d);
797     }
798     /*  Field the step_size input, if any, but don't do anything special  */
799     (void)UpdateMultitypeData(new, &new->stepper.value_step,
800 			      &current->stepper.value_step);
801     /*  Check value and limits for consistency and adjust if nescessary  */
802     if( (i>0) && (new->composite.num_children > 0) )
803 	XtSetValues(new->composite.children[0], wargs, i);
804 
805     ComputeLayout(new, &loc);
806     if (XtIsRealized ((Widget)new)) LayoutStepper (new);
807 
808     if (need_new_width) new->core.width = loc.field_width;
809     if (need_new_height) new->core.height = loc.field_height;
810     return TRUE;
811 }
812 
813 
814 /*  Subroutine:	Destroy
815  *  Effect:	Frees resources before widget is destroyed
816  */
Destroy(XmStepperWidget sw)817 static void Destroy( XmStepperWidget sw )
818 {
819     XtRemoveAllCallbacks((Widget)sw, XmNarmCallback);
820     XtRemoveAllCallbacks((Widget)sw, XmNactivateCallback);
821 }
822 
823 
824 /*  Subroutine:	Resize
825  *  Purpose:	Calculate the drawing area and redraw the widget
826  */
Resize(XmStepperWidget sw)827 static void Resize( XmStepperWidget sw )
828 {
829     LayoutStepper(sw);
830 }
831 
832 
833 /*  Subroutine:	ChangeManaged
834  *  Effect:	Makes sure everyone is in their places before the curtain opens
835  */
ChangeManaged(XmStepperWidget sw)836 static void ChangeManaged( XmStepperWidget sw )
837 {
838     LayoutStepper(sw);
839 }
840 
841 
842 /*  Subroutine:	Redisplay
843  *  Effect:	Does redisplays on the component gadgets (gadgets must be
844  *		handled differently from widgets)
845  */
Redisplay(XmStepperWidget sw,XEvent * event,Region region)846 static void Redisplay( XmStepperWidget sw, XEvent* event, Region region)
847 {
848 }
849 
850 
851 /*  Subroutine:	Arm
852  *  Effect:	Processes "arm" type actions in the stepper widget field that
853  *		might belong to its gadgets.
854  */
Arm(XmStepperWidget sw,XButtonEvent * event)855 static void Arm( XmStepperWidget sw, XButtonEvent* event )
856 {
857 }
858 
859 
860 /*  Subroutine:	Activate
861  *  Effect:	Processes "activate" and "disarm" type actions in the stepper
862  *		widget field that might belong to its gadgets.
863  */
Activate(XmStepperWidget sw,XButtonPressedEvent * event)864 static void Activate( XmStepperWidget sw, XButtonPressedEvent* event )
865 {
866 }
867 
868 
869 /*  Subroutine:	CallFromNumber
870  *  Purpose:	Callback routine from number widget to allow/disallow stepper
871  *		to manipulate the value, or to set a new value.
872  */
CallFromNumber(Widget w,XmStepperWidget sw,XmDoubleCallbackStruct * call_data)873 static void CallFromNumber( Widget	w,
874 			    XmStepperWidget sw,
875 			    XmDoubleCallbackStruct* call_data )
876 {
877 
878     if( call_data->reason == XmCR_ARM )
879     {
880 	if( sw->stepper.timer )
881 	    XtRemoveTimeOut(sw->stepper.timer);
882 	sw->stepper.allow_input = FALSE;
883     }
884     else if( call_data->reason == XmCR_DISARM )
885     {
886 	sw->stepper.allow_input = TRUE;
887     }
888     else if( call_data->reason == XmCR_ACTIVATE )
889     {
890 	sw->stepper.value.d = call_data->value;
891 	if ((sw->stepper.data_type == FLOAT) ||
892 	    (sw->stepper.data_type == INTEGER) )
893 	    sw->stepper.value.f = (float)call_data->value;
894 	if (sw->stepper.data_type == INTEGER)
895 	{
896 	    if( call_data->value >= 0.0 )
897 		sw->stepper.value.i = (int)(call_data->value + 0.5);
898 	    else
899 		sw->stepper.value.i = (int)(call_data->value - 0.5);
900 	}
901     }
902     if (call_data->reason == XmCR_ACTIVATE)
903     {
904 	sw->stepper.value_changed = TRUE;
905 	CallbackActivate(sw);
906     }
907 }
908 
909 
910 #define MAX_VAL(a,b) ((a)>(b)?(a):(b))
911 /*  Subroutine:	ComputeLayout
912  *  Effect:	Calculates the sizes and positions for all components
913  */
ComputeLayout(XmStepperWidget sw,struct layout * loc)914 static void ComputeLayout( XmStepperWidget sw, struct layout *loc )
915 {
916     XtWidgetGeometry request, reply;
917 
918     if( sw->composite.num_children > 0 )
919     {
920 	/*  Calculate the size of the number widget  */
921 	request.request_mode = CWWidth | CWHeight;
922 	request.width = 1;
923 	request.height = 1;
924 	(void)XtQueryGeometry(sw->composite.children[0], &request, &reply);
925 	if( sw->stepper.resize_to_number )
926 	{
927 	    loc->number_width = reply.width;
928 	    loc->number_height = reply.height;
929 	}
930 	else
931 	{
932 /*	    loc->number_width =
933 	      MAX_VAL(reply.width, sw->composite.children[0]->core.width);
934 	    loc->number_height =
935 	      MAX_VAL(reply.height, sw->composite.children[0]->core.height); */
936 	    loc->number_width = sw->composite.children[0]->core.width;
937 	    loc->number_height = sw->composite.children[0]->core.height;
938 	}
939     }
940     else if( loc->number_height <= 4 )
941     {
942 	loc->number_width = (sw->stepper.num_digits * 6) + 4;
943 	loc->number_height = 19;
944     }
945 
946     /*  Arrows have height of label and are square or full width  */
947     loc->arrow_height = loc->number_height;
948     loc->up_left_x = loc->up_left_y = 0;
949     if( (sw->stepper.increase_direction == XmARROW_LEFT)
950        || (sw->stepper.increase_direction == XmARROW_RIGHT) )
951     {
952 	loc->field_height = loc->number_height;
953 	loc->arrow_width = loc->number_height;
954 	loc->number_y = 0;
955 	loc->down_right_y = 0;
956 	loc->field_width = loc->number_width + (2*loc->number_height) + 2;
957 	if (sw->stepper.alignment == XmALIGNMENT_CENTER) {
958 
959 	   int midpt;
960 	   loc->field_width = MAX_VAL(loc->field_width, sw->core.width);
961 	   /*midpt = loc->field_width/2;*/
962 	   midpt = sw->core.width >> 1;
963 
964 	   loc->number_x = midpt - (loc->number_width/2);
965 	   loc->down_right_x = loc->number_x + loc->number_width + 2;
966 	   loc->up_left_x = loc->number_x - (loc->arrow_width + 2);
967 
968 	   loc->up_left_y = loc->number_y = loc->down_right_y = 0;
969 	   if (sw->core.height > loc->number_height) {
970 	   	loc->up_left_y = loc->number_y = loc->down_right_y =
971 		(sw->core.height - loc->number_height)>>1;
972 	   }
973 	} else if (sw->stepper.alignment == XmALIGNMENT_BEGINNING) {
974 	    loc->down_right_x = loc->field_width - loc->arrow_width;
975 	    loc->number_x = loc->arrow_width + 1;
976 
977 	} else { /* must == XmALIGNMENT_END */
978 	    loc->down_right_x = sw->core.width - (loc->arrow_width );
979 	    loc->number_x = loc->down_right_x - (2+loc->number_width);
980 	    loc->up_left_x = loc->number_x - (loc->arrow_width + 2);
981 	    loc->up_left_y = 0;
982 	}
983     }
984     else
985     {
986 	loc->field_height = (3 * loc->number_height) + 2;
987 	loc->field_width = loc->number_width;
988 	loc->arrow_width = loc->number_width;
989 	loc->down_right_x = 0;
990 	loc->down_right_y = loc->field_height - loc->arrow_height;
991 	loc->number_x = 0;
992 	loc->number_y = loc->arrow_height + 1;
993     }
994 }
995 #undef MAX_VAL
996 
997 
998 /*  Subroutine:	LayoutStepper
999  *  Effect:	Moves and resizes anything that is out of shape or position
1000  */
LayoutStepper(XmStepperWidget sw)1001 static void LayoutStepper( XmStepperWidget sw )
1002 {
1003     Widget number, up_left, down_right;
1004     struct layout loc;
1005 
1006     ComputeLayout(sw, &loc);
1007     if( sw->composite.num_children > 0 )
1008     {
1009 	number = sw->composite.children[0];
1010 	if( (loc.number_x != number->core.x) ||
1011 	    (loc.number_y != number->core.y) )
1012 	    XtMoveWidget(number, loc.number_x, loc.number_y);
1013 	if( (loc.number_width != number->core.width) ||
1014 	    (loc.number_height != number->core.height) )
1015 	    XtResizeWidget(number, loc.number_width, loc.number_height,0);
1016     }
1017     if( sw->composite.num_children > 1 )
1018     {
1019 	up_left = sw->composite.children[1];
1020 	if( (loc.up_left_x != up_left->core.x) ||
1021 	    (loc.up_left_y != up_left->core.y) )
1022 	    XtMoveWidget(up_left, loc.up_left_x, loc.up_left_y);
1023 	if( (loc.arrow_width != up_left->core.width) ||
1024 	    (loc.arrow_height != up_left->core.height) )
1025 	    XtResizeWidget(up_left, loc.arrow_width, loc.arrow_height,0);
1026     }
1027     if( sw->composite.num_children > 2 )
1028     {
1029 	down_right = sw->composite.children[2];
1030 	if( (loc.down_right_x != down_right->core.x) ||
1031 	    (loc.down_right_y != down_right->core.y) )
1032 	    XtMoveWidget(down_right, loc.down_right_x, loc.down_right_y);
1033 	if( (loc.arrow_width != down_right->core.width) ||
1034 	    (loc.arrow_height != down_right->core.height) )
1035 	    XtResizeWidget(down_right, loc.arrow_width, loc.arrow_height,0);
1036     }
1037 }
1038 
1039 
1040 /*  Subroutine:	VerifyValueRange
1041  *  Effect:	Checks limits and then value for consistency with rules.
1042  */
VerifyValueRange(XmStepperWidget sw,Boolean checkStep)1043 static void VerifyValueRange( XmStepperWidget sw , Boolean checkStep)
1044 {
1045 int d1,d2, expon;
1046 char string[32];
1047     /*
1048      *  Make sure the minimum and maximum value settings are valid.
1049      */
1050     if( sw->stepper.value_minimum.d > sw->stepper.value_maximum.d )
1051     {
1052 /*        XtWarning(MESSAGE1); */
1053 	sw->stepper.value_minimum.d = sw->stepper.value_maximum.d;
1054 	sw->stepper.value_minimum.f = sw->stepper.value_minimum.f;
1055 	sw->stepper.value_minimum.i = sw->stepper.value_maximum.i;
1056     }
1057     if( sw->stepper.value.d > sw->stepper.value_maximum.d )
1058     {
1059 /*        XtWarning(MESSAGE2); */
1060 	sw->stepper.value.d = sw->stepper.value_maximum.d;
1061 	sw->stepper.value.f = sw->stepper.value_maximum.f;
1062 	sw->stepper.value.i = sw->stepper.value_maximum.i;
1063     }
1064     if( sw->stepper.value.d < sw->stepper.value_minimum.d )
1065     {
1066 /*        XtWarning(MESSAGE3); */
1067 	sw->stepper.value.d = sw->stepper.value_minimum.d;
1068 	sw->stepper.value.f = sw->stepper.value_minimum.f;
1069 	sw->stepper.value.i = sw->stepper.value_minimum.i;
1070     }
1071 
1072     /*
1073      * Check that the incr/decr amount is not overly precise
1074      * because the rounding arithmetic would make it either 0 or 1.
1075      * ... but don't do anything about it!
1076      */
1077     if (checkStep) {
1078        sprintf(string, "%8.1e", sw->stepper.value_step.d);
1079        sscanf(string, "%d.%de%d", &d1, &d2, &expon);
1080        if ((expon<0)&&(-expon>sw->stepper.decimal_places))
1081        {
1082 	   XmNumberWarningCallbackStruct nws;
1083 	   nws.message = MESSAGE4;
1084 	   nws.event = 0;
1085 	   nws.reason = XmCR_NUM_WARN_EXCESS_PRECISION;
1086 	   WarningCallback ((Widget)sw, sw, &nws);
1087        }
1088     }
1089 }
1090 
1091 
1092 /*  Subroutine:	IncrementStepper
1093  *  Effect:	Increment or decrement the stepper value and display by the
1094  *		 given step, up to the range limits.
1095  */
IncrementStepper(XmStepperWidget sw,Boolean increase,double step_size)1096 static Boolean IncrementStepper( XmStepperWidget sw,
1097 				 Boolean increase, double step_size )
1098 {
1099     double 	rvalue;
1100     double 	new_value;
1101     double 	value = sw->stepper.value.d;
1102     double 	expon;
1103     double 	cross_under;
1104     double 	cross_over;
1105     int         expon2;
1106     int 	d1;
1107     int 	d2;
1108     char   	string[100];
1109     Arg		wargs[5];
1110 
1111     if( increase )
1112     {
1113 	value += step_size;
1114     }
1115     else
1116     {
1117 	value -= step_size;
1118     }
1119     new_value = value;
1120 
1121 #if 0
1122     double	ddv, diff;
1123     int dv;
1124     Boolean neg;
1125 /* This code was added so that stepper and slider would be consistent.
1126    Taking it out because it's undesirable behavior for a stepper.  Leaving
1127    it in slider though.
1128 */
1129     /*
1130      * round the value to a multiple of step_size - gresh395
1131      */
1132     if (step_size)
1133     {
1134        if (new_value < 0.0) neg = True; else neg = False;
1135        ddv = new_value / step_size;
1136        dv = (int)ddv;
1137        diff = ddv - dv;
1138        if (diff >= 0.5) dv++;
1139        new_value = step_size * dv;
1140        if ((neg) && (new_value > 0.0)) new_value = -new_value;
1141        value = new_value;
1142     }
1143 #endif
1144 
1145     /*
1146      * Round the value if decimal_places != -1.
1147      */
1148 
1149     if (sw->stepper.decimal_places != -1)
1150     {
1151 	XtSetArg(wargs[0], XmNcrossUnder, &cross_under);
1152 	XtSetArg(wargs[1], XmNcrossOver,  &cross_over);
1153 	XtGetValues(sw->stepper.child[0], wargs, 2);
1154 	sprintf(string, "%8.1e", value);
1155 	sscanf(string, "%d.%de%d", &d1, &d2, &expon2);
1156 	if (expon2 < 0)
1157 	{
1158 	    if (( -expon2 > sw->stepper.decimal_places) &&
1159 		(((value < cross_under)&&(value > 0)) ||
1160 		 ((-value < cross_under)&&(value < 0))) )
1161 		expon = pow((double)10,
1162 			(double)sw->stepper.decimal_places-expon2);
1163 	    else
1164 		expon = pow((double)10, (double)sw->stepper.decimal_places);
1165 	}
1166 	else
1167 	{
1168 	    if (( expon2 > sw->stepper.decimal_places) &&
1169 		(((value > cross_over)&&(value > 0)) ||
1170 		 ((-value > cross_over)&&(value < 0))) )
1171 		expon = 1/pow((double)10,
1172 			(double)expon2 - sw->stepper.decimal_places);
1173 	    else
1174 		expon = pow((double)10, (double)sw->stepper.decimal_places);
1175 	}
1176 	value = value * expon;
1177 	if (value < 0)
1178 	{
1179 	    value = value - 0.5;
1180 	}
1181 	else
1182 	{
1183 	    value = value + 0.5;
1184 	}
1185 	if (fabs(value) < INT_MAX)
1186 	{
1187 	    rvalue = trunc(value);
1188 	    value = rvalue / expon;
1189 	}
1190 	else /* Too large to round */
1191 	{
1192 	    value = new_value;
1193 	}
1194     }
1195 
1196     if( increase )
1197     {
1198 	if( value > sw->stepper.value_maximum.d )
1199 	{
1200 	    if( sw->stepper.roll_over )
1201 		value = sw->stepper.value_minimum.d
1202 		    + (value - sw->stepper.value_maximum.d);
1203 	    else
1204 		value = sw->stepper.value_maximum.d;
1205 	}
1206 	if( value < sw->stepper.value_minimum.d )
1207 	{
1208 	    if( sw->stepper.roll_over )
1209 		value = sw->stepper.value_maximum.d
1210 		    + (value - sw->stepper.value_minimum.d);
1211 	    else
1212 		value = sw->stepper.value_minimum.d;
1213 	}
1214     } else {
1215 	if( value < sw->stepper.value_minimum.d )
1216 	{
1217 	    if( sw->stepper.roll_over )
1218 		value = sw->stepper.value_maximum.d
1219 		  + (value - sw->stepper.value_minimum.d);
1220 	    else
1221 		value = sw->stepper.value_minimum.d;
1222 	}
1223 	if( value > sw->stepper.value_maximum.d )
1224 	{
1225 	    if( sw->stepper.roll_over )
1226 		value = sw->stepper.value_minimum.d
1227 		  + (value - sw->stepper.value_maximum.d);
1228 	    else
1229 		value = sw->stepper.value_maximum.d;
1230 	}
1231     }
1232     if( value != sw->stepper.value.d )
1233     {
1234 	sw->stepper.value.d = value;
1235 	sw->stepper.value_changed  = TRUE;
1236 	if ((sw->stepper.data_type == FLOAT) ||
1237 	    (sw->stepper.data_type == INTEGER) )
1238 	    sw->stepper.value.f = (float)sw->stepper.value.d;
1239 	if (sw->stepper.data_type == INTEGER)
1240 	{
1241 	    if( sw->stepper.value.d >= 0.0 )
1242 		sw->stepper.value.i = (int)(sw->stepper.value.d + 0.5);
1243 	    else
1244 		sw->stepper.value.i = (int)(sw->stepper.value.d - 0.5);
1245 	}
1246 	if( sw->composite.children[0] )
1247 	    XmChangeNumberValue((XmNumberWidget)sw->composite.children[0],
1248 				value);
1249     }
1250 
1251     return TRUE;
1252 }
1253 
1254 /*  Subroutine:	ButtonArmEvent
1255  *  Effect:	Check event that this arming (activation) can be accepted and
1256  *		 set up the next auto-repeat for an armed button.
1257  */
ButtonArmEvent(Widget w,XmStepperWidget sw,XtCallbackProc callback_proc)1258 static Boolean ButtonArmEvent( Widget w, XmStepperWidget sw,
1259 			       XtCallbackProc callback_proc )
1260 {
1261     if( (sw->stepper.timer == (XtIntervalId)NULL) ||
1262         (sw->stepper.timeout_proc != callback_proc) )
1263     {
1264 	sw->stepper.repeat_count = 0;
1265 	sw->stepper.timeout_proc = callback_proc;
1266 	sw->stepper.active_widget = w;
1267 	sw->stepper.interval = sw->stepper.time_interval;
1268     }
1269     else
1270     {
1271 	if( (sw->stepper.interval -=
1272 	     (sw->stepper.interval / sw->stepper.time_ddelta))
1273 	    < xmStepperClassRec.stepper_class.minimum_time_interval )
1274 	    sw->stepper.interval =
1275 	      xmStepperClassRec.stepper_class.minimum_time_interval;
1276     }
1277     sw->stepper.timer =
1278 	XtAppAddTimeOut(XtWidgetToApplicationContext(w),
1279 			sw->stepper.interval, (XtTimerCallbackProc)RepeatDigitButton, sw);
1280     return TRUE;
1281 }
1282 
1283 
1284 /*  Subroutine:	WarningCallback
1285  *  Effect:	Increase stepper value when increase button is "armed"
1286  */
1287 /* ARGSUSED */
WarningCallback(Widget w,XmStepperWidget sw,XmNumberWarningCallbackStruct * call_data)1288 static void WarningCallback( Widget w, XmStepperWidget sw,
1289 			    XmNumberWarningCallbackStruct *call_data )
1290 {
1291     XtCallCallbacks((Widget)sw, XmNwarningCallback, call_data);
1292 }
1293 /*  Subroutine:	ButtonIncrease
1294  *  Effect:	Increase stepper value when increase button is "armed"
1295  */
1296 /* ARGSUSED */
ButtonIncrease(Widget w,XmStepperWidget sw,XmAnyCallbackStruct * call_data)1297 static void ButtonIncrease( Widget w, XmStepperWidget sw,
1298 			    XmAnyCallbackStruct *call_data )
1299 {
1300     if(   ButtonArmEvent(w, sw, (XtCallbackProc)ButtonIncrease)
1301        && IncrementStepper(sw, TRUE, sw->stepper.value_step.d) )
1302 	CallbackStep(sw, TRUE);
1303 }
1304 
1305 
1306 /*  Subroutine:	ButtonDecrease
1307  *  Effect:	Decrease stepper value when increase button is "armed"
1308  */
1309 /* ARGSUSED */
ButtonDecrease(Widget w,XmStepperWidget sw,XmAnyCallbackStruct * call_data)1310 static void ButtonDecrease( Widget w, XmStepperWidget sw,
1311 			    XmAnyCallbackStruct *call_data )
1312 {
1313     if(   ButtonArmEvent(w, sw, (XtCallbackProc)ButtonDecrease)
1314        && IncrementStepper(sw, FALSE, sw->stepper.value_step.d) )
1315 	CallbackStep(sw, FALSE);
1316 }
1317 
1318 
1319 /*  Subroutine:	ButtonIsReleased
1320  *  Effect:	Release auto-repeat when button is disarmed.
1321  */
1322 /* ARGSUSED */
ButtonIsReleased(Widget w,XmStepperWidget sw,XmAnyCallbackStruct * call_data)1323 static void ButtonIsReleased( Widget w, XmStepperWidget sw,
1324 			      XmAnyCallbackStruct *call_data )
1325 {
1326     /*  Button press or release for another button is not of interest  */
1327     if( sw->stepper.timer )
1328     {
1329 	if( sw->stepper.timer )
1330 	    {
1331 	    XtRemoveTimeOut(sw->stepper.timer);
1332 	    }
1333 	sw->stepper.active_widget = NULL;
1334 	sw->stepper.repeat_count = 0;
1335 	sw->stepper.timeout_proc = NULL;
1336 	sw->stepper.timer = (XtIntervalId)NULL;
1337 	CallbackActivate(sw);
1338     }
1339 }
1340 
1341 
1342 /*  Subroutine:	CallbackActivate
1343  *  Purpose:	Call registered callbacks to report final value change
1344  */
CallbackActivate(XmStepperWidget sw)1345 static void CallbackActivate( XmStepperWidget sw )
1346 {
1347     XmDoubleCallbackStruct call_value;
1348 
1349     /* don't call the callbacks if value doesn't change */
1350     if(!sw->stepper.value_changed)
1351 	return;
1352 
1353     call_value.value = sw->stepper.value.d;
1354     call_value.reason = XmCR_ACTIVATE;
1355     XtCallCallbacks((Widget)sw, XmNactivateCallback, &call_value);
1356     sw->stepper.value_changed = FALSE;
1357 }
1358 
1359 
1360 /*  Subroutine:	CallbackStep
1361  *  Purpose:	Call registered callbacks to report value change while stepping
1362  */
CallbackStep(XmStepperWidget sw,Boolean increase)1363 static void CallbackStep( XmStepperWidget sw, Boolean increase )
1364 {
1365     XmDoubleCallbackStruct call_value;
1366 
1367     call_value.value = sw->stepper.value.d;
1368     call_value.reason = increase ? XmCR_INCREMENT : XmCR_DECREMENT;
1369     XtCallCallbacks((Widget)sw, XmNactivateCallback, &call_value);
1370 }
1371 
1372 
1373 /*  Subroutine:	RepeatDigitButton
1374  *  Effect:	Fake a button activate event for the currently active button
1375  *		 (called by the timer for autorepeat).
1376  */
RepeatDigitButton(XmStepperWidget sw,XtIntervalId * id)1377 static void RepeatDigitButton( XmStepperWidget sw, XtIntervalId *id )
1378 {
1379     XmAnyCallbackStruct call_data;
1380 
1381     /*  If not our event or repetition button was cancelled, ignore  */
1382     if( *id != sw->stepper.timer )
1383 	{
1384 	return;
1385 	}
1386     call_data.event = NULL;
1387     call_data.reason = XmCR_REPEAT_ARM;
1388     (sw->stepper.timeout_proc)(sw->stepper.active_widget, sw, &call_data);
1389 }
1390 
1391 static
UpdateMultitypeData(XmStepperWidget sw,MultitypeData * new,MultitypeData * current)1392 Boolean UpdateMultitypeData(XmStepperWidget sw, MultitypeData* new,
1393 		MultitypeData* current )
1394 {
1395 
1396     if (sw->stepper.data_type == INTEGER)
1397     {
1398         if( new->i != current->i )
1399         {
1400             new->d = (double)new->i;
1401             new->f = (float)new->i;
1402 	    return True;
1403         }
1404     }
1405     else if (sw->stepper.data_type == FLOAT)
1406     {
1407         if( new->f != current->f )
1408         {
1409             new->d = (double)new->f;
1410             new->i = 0;
1411 	    return True;
1412         }
1413     }
1414     else if (sw->stepper.data_type == DOUBLE)
1415     {
1416         if( new->d != current->d )
1417         {
1418             new->f = 0;
1419             new->i = 0;
1420 	    return True;
1421         }
1422     }
1423     return False;
1424 }
1425 
1426 
1427 
1428 /*  Subroutine:	XmCreateStepper
1429  *  Purpose:	This function creates and returns a Stepper widget.
1430  */
XmCreateStepper(Widget parent,String name,ArgList args,Cardinal num_args)1431 Widget XmCreateStepper( Widget parent, String name,
1432 			ArgList args, Cardinal num_args )
1433 {
1434     return XtCreateWidget(name, xmStepperWidgetClass, parent, args, num_args);
1435 }
1436