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 ¤t->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 ¤t->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, ¤t->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 ¤t->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