1 /**
2  *
3  * $Header: /cvsroot/lesstif/lesstif/lib/Xm-2.1/Scale.c,v 1.2 2004/10/27 20:57:58 dannybackx Exp $
4  *
5  * Copyright (C) 1995 Free Software Foundation, Inc.
6  * Copyright � 1995-2002, 2004 LessTif Development Team
7  *
8  * This file is part of the GNU LessTif Library.
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public
21  * License along with this library; if not, write to the Free
22  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  *
24  **/
25 
26 static const char rcsid[] = "$Id: Scale.c,v 1.2 2004/10/27 20:57:58 dannybackx Exp $";
27 
28 #include <LTconfig.h>
29 
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <limits.h>
33 #include <math.h>
34 
35 #include <XmI/XmI.h>
36 #include <Xm/XmP.h>
37 #include <Xm/ScaleP.h>
38 #include <Xm/LabelGP.h>
39 #include <Xm/ScrollBarP.h>
40 #include <Xm/BulletinBP.h>
41 #include <Xm/MenuShellP.h>
42 #include <Xm/VendorSP.h>
43 #include <Xm/VendorSEP.h>
44 
45 #include <XmI/DebugUtil.h>
46 
47 
48 #define USE_LAYOUT	1
49 
50 #define CHILD_LAB	0
51 #define CHILD_SB	1
52 
53 /* FIX ME/BUGS
54  *   - highlight
55  */
56 
57 /*
58  * these values come from behavior observation of M*tif.  Change at your own
59  * risk
60  *
61  * Hmm, I've observed HSLIDERSIZE to be 30 (M*tif 1.2.2) -- PvH
62  */
63 #define SCB_MAX		1000000000
64 #define SCB_MIN		0
65 #define HSLIDERSIZE	/*40*/30
66 #define VSLIDERSIZE	12
67 #define MIN_SLIDE	4
68 
69 #define SB_TRANSVERSAL_SIZE	15
70 #define SB_LONGITUDAL_SIZE	100
71 
72 /* T. Straumann: special value to indicate that the value rectangle position
73  * is invalid and hence must not be erased.
74  */
75 #define SHOW_VALUE_X_INVALID -65536
76 
77 #define Scale_ShadowThickness(x) MGR_ShadowThickness(x)
78 
79 static void class_initialize(void);
80 static void class_part_initialize(WidgetClass w_class);
81 static void initialize(Widget request, Widget new_w,
82 		       ArgList args, Cardinal *num_args);
83 static void destroy(Widget w);
84 static void realize(Widget w, XtValueMask *value_mask,
85 		    XSetWindowAttributes *attributes);
86 static Boolean set_values(Widget current, Widget request, Widget new_w,
87 			  ArgList args, Cardinal *num_args);
88 static XtGeometryResult query_geometry(Widget w,
89 				       XtWidgetGeometry *request,
90 				       XtWidgetGeometry *reply);
91 static XtGeometryResult geometry_manager(Widget w,
92 					 XtWidgetGeometry *request,
93 					 XtWidgetGeometry *reply);
94 static void expose(Widget w, XEvent *event, Region region);
95 static void resize(Widget w);
96 static void change_managed(Widget w);
97 
98 #if 0
99 static void insert_child(Widget w);
100 #endif
101 
102 static XmKidGeometry _XmScalePreferredSize(Widget scale, Widget child,
103 					   XtWidgetGeometry *childgeom,
104 					   Dimension *w, Dimension *ht);
105 static XtGeometryResult _XmScaleGeomRequest(Widget scale,
106 					    Dimension *wd, Dimension *ht);
107 static void _XmScaleLayout(Widget scale, XmKidGeometry boxes,
108 			   Widget child, XtWidgetGeometry *childgeom,
109 			   Dimension curw, Dimension curh);
110 static void _XmScaleConfigureChildren(Widget scale,
111 				      Widget child,
112 				      XmKidGeometry boxes);
113 static int _XmScaleConvertWidthToSliderSize(Widget w);
114 static int _XmScaleConvertSCBValueToScaleValue(Widget w, int value);
115 static int _XmScaleConvertScaleValueToSCBValue(Widget w);
116 static void _XmScaleConvertScaleIncrementToSCBIncrements(Widget w,
117 							 int* inc,
118 							 int* page_inc);
119 static void _ScaleValueChanged(Widget sb, XtPointer cd, XtPointer data);
120 static void _ScaleDrag(Widget sb, XtPointer cd, XtPointer data);
121 static void computeValueSize(Widget w);
122 static void showValue(Widget w, int scb_value, int scale_value);
123 
124 #if 0
125 static void GetFocus(Widget w, XEvent *event,
126 		     String *params, Cardinal *num_params);
127 static void LoseFocus(Widget w, XEvent *event,
128 		      String *params, Cardinal *num_params);
129 #endif
130 
131 static void _XmScaleProcessingDirectionDefault(Widget w,
132 					       int offset,
133 					       XrmValue *val);
134 
135 /*
136  * Resources for the scale class
137  */
138 #define Offset(field) XtOffsetOf(XmScaleRec, scale.field)
139 static XtResource resources[] =
140 {
141     {
142 	XmNshadowThickness, XmCShadowThickness, XmRHorizontalDimension,
143 	sizeof(Dimension), XtOffsetOf(XmScaleRec, manager.shadow_thickness),
144 	XmRImmediate, (XtPointer)2
145     },
146     {
147 	XmNvalue, XmCValue, XmRInt,
148 	sizeof(int), Offset(value),
149 	XmRImmediate, (XtPointer)INT_MAX
150     },
151     {
152 	XmNmaximum, XmCMaximum, XmRInt,
153 	sizeof(int), Offset(maximum),
154 	XmRImmediate, (XtPointer)100
155     },
156     {
157 	XmNminimum, XmCMinimum, XmRInt,
158 	sizeof(int), Offset(minimum),
159 	XmRImmediate, (XtPointer)0
160     },
161     {
162 	XmNorientation, XmCOrientation, XmROrientation,
163 	sizeof(unsigned char), Offset(orientation),
164 	XmRImmediate, (XtPointer)XmVERTICAL
165     },
166     {
167 	XmNprocessingDirection, XmCProcessingDirection, XmRProcessingDirection,
168 	sizeof(unsigned char), Offset(processing_direction),
169 	XmRCallProc, (XtPointer)_XmScaleProcessingDirectionDefault
170     },
171     {
172 	XmNtitleString, XmCTitleString, XmRXmString,
173 	sizeof(XmString), Offset(title),
174 	XtRImmediate, (XtPointer)NULL
175     },
176     {
177 	XmNfontList, XmCFontList, XmRFontList,
178 	sizeof(XmFontList), Offset(font_list),
179 	XtRImmediate, (XtPointer)NULL
180     },
181     {
182 	XmNshowValue, XmCShowValue, XmRBoolean,
183 	sizeof(Boolean), Offset(show_value),
184 	XmRImmediate, (XtPointer)False
185     },
186     {
187 	XmNdecimalPoints, XmCDecimalPoints, XmRShort,
188 	sizeof(short), Offset(decimal_points),
189 	XmRImmediate, (XtPointer)(short)0
190     },
191     {
192 	XmNscaleWidth, XmCScaleWidth, XmRHorizontalDimension,
193 	sizeof(Dimension), Offset(scale_width),
194 	XmRImmediate, (XtPointer)0
195     },
196     {
197 	XmNscaleHeight, XmCScaleHeight, XmRVerticalDimension,
198 	sizeof(Dimension), Offset(scale_height),
199 	XmRImmediate, (XtPointer)0
200     },
201     {
202 	XmNhighlightThickness, XmCHighlightThickness, XmRHorizontalDimension,
203 	sizeof(Dimension), Offset(highlight_thickness),
204 	XmRImmediate, (XtPointer)2
205     },
206     {
207 	XmNhighlightOnEnter, XmCHighlightOnEnter, XmRBoolean,
208 	sizeof(Boolean), Offset(highlight_on_enter),
209 	XmRImmediate, (XtPointer)False
210     },
211     {
212 	XmNvalueChangedCallback, XmCCallback, XmRCallback,
213 	sizeof(XtCallbackList), Offset(value_changed_callback),
214 	XmRCallback, (XtPointer)NULL
215     },
216     {
217 	XmNdragCallback, XmCCallback, XmRCallback,
218 	sizeof(XtCallbackList), Offset(drag_callback),
219 	XmRCallback, (XtPointer)NULL
220     },
221 #if XmVERSION > 1
222     {
223 	XmNeditable, XmCEditable, XmRBoolean,
224 	sizeof(Boolean), Offset(editable),
225 	XmRImmediate, (XtPointer)True
226     },
227 #endif
228     {
229 	XmNscaleMultiple, XmCScaleMultiple, XmRInt,
230 	sizeof(int), Offset(scale_multiple),
231 	XmRImmediate, (XtPointer)0
232     }
233 };
234 
235 static XmSyntheticResource syn_resources[] =
236 {
237     {
238 	XmNtitleString,
239 	sizeof(XmString), Offset(title),
240 	_XmExportXmString, NULL
241     },
242     {
243 	XmNscaleWidth,
244 	sizeof(Dimension), Offset(scale_width),
245 	_XmFromHorizontalPixels, _XmToHorizontalPixels
246     },
247     {
248 	XmNscaleHeight,
249 	sizeof(Dimension), Offset(scale_height),
250 	_XmFromVerticalPixels, _XmToVerticalPixels
251     },
252 };
253 
254 #if 0
255 static char defaultTranslations[] =
256     "<FocusIn>: FocusIn() \n\
257      <FocusOut>: FocusOut()";
258 
259 static XtActionsRec actions[] =
260 {
261     {"FocusIn", GetFocus},
262     {"FocusOut", LoseFocus}
263 };
264 #endif
265 
266 static XmBaseClassExtRec _XmScaleCoreClassExtRec = {
267     /* next_extension            */ NULL,
268     /* record_type               */ NULLQUARK,
269     /* version                   */ XmBaseClassExtVersion,
270     /* size                      */ sizeof(XmBaseClassExtRec),
271     /* initialize_prehook        */ NULL,
272     /* set_values_prehook        */ NULL,
273     /* initialize_posthook       */ NULL,
274     /* set_values_posthook       */ NULL,
275     /* secondary_object_class    */ NULL,
276     /* secondary_object_create   */ NULL,
277     /* get_secondary_resources   */ NULL,
278     /* fast_subclass             */ { 0 },
279     /* get_values_prehook        */ NULL,
280     /* get_values_posthook       */ NULL,
281     /* class_part_init_prehook   */ NULL,
282     /* class_part_init_posthook  */ NULL,
283     /* ext_resources             */ NULL,
284     /* compiled_ext_resources    */ NULL,
285     /* num_ext_resources         */ 0,
286     /* use_sub_resources         */ False,
287     /* widget_navigable          */ XmInheritWidgetNavigable, /* Motif has one */
288     /* focus_change              */ XmInheritFocusChange, /* Motif has NULL */
289     /* wrapper_data              */ NULL
290 };
291 
292 #if 0
293 static XmManagerClassExtRec _XmScaleMClassExtRec = {
294     /* next_extension            */ NULL,
295     /* record_type               */ NULLQUARK,
296     /* version                   */ XmManagerClassExtVersion,
297     /* record_size               */ sizeof(XmManagerClassExtRec),
298     /* traversal_children        */ NULL /* FIX ME */
299 };
300 #endif
301 
302 XmScaleClassRec xmScaleClassRec =
303 {
304     /* Core class part */
305     {
306 	/* superclass            */ (WidgetClass) & xmManagerClassRec,
307 	/* class_name            */ "XmScale",
308 	/* widget_size           */ sizeof(XmScaleRec),
309 	/* class_initialize      */ class_initialize,
310 	/* class_part_initialize */ class_part_initialize,
311 	/* class_inited          */ False,
312 	/* initialize            */ initialize,
313 	/* initialize_hook       */ NULL,
314 	/* realize               */ realize,
315 	/* actions               */ NULL /*actions*/,
316 	/* num_actions           */ 0 /*XtNumber(actions)*/,
317 	/* resources             */ resources,
318 	/* num_resources         */ XtNumber(resources),
319 	/* xrm_class             */ NULLQUARK,
320 	/* compress_motion       */ True,
321 	/* compress_exposure     */ XtExposeCompressMaximal,
322 	/* compress_enterleave   */ True,
323 	/* visible_interest      */ False,
324 	/* destroy               */ destroy,
325 	/* resize                */ resize,
326 	/* expose                */ expose,
327 	/* set_values            */ set_values,
328 	/* set_values_hook       */ NULL,
329 	/* set_values_almost     */ XtInheritSetValuesAlmost,
330 	/* get_values_hook       */ NULL,
331 	/* accept_focus          */ NULL,
332 	/* version               */ XtVersion,
333 	/* callback offsets      */ NULL,
334 	/* tm_table              */ XtInheritTranslations /*defaultTranslations*/,
335 	/* query_geometry        */ query_geometry,
336 	/* display_accelerator   */ NULL /*XtInheritDisplayAccelerator*/,
337 	/* extension             */ (XtPointer)&_XmScaleCoreClassExtRec
338     },
339     /* Composite class part */
340     {
341 	/* geometry manager */ geometry_manager,
342 	/* change_managed   */ change_managed,
343 	/* insert_child     */ XtInheritInsertChild /*insert_child*/,
344 	/* delete_child     */ XtInheritDeleteChild,
345 	/* extension        */ NULL,
346     },
347     /* Constraint class part */
348     {
349 	/* subresources      */ NULL,
350 	/* subresource_count */ 0,
351 	/* constraint_size   */ 0,
352 	/* initialize        */ NULL,
353 	/* destroy           */ NULL,
354 	/* set_values        */ NULL,
355 	/* extension         */ NULL,
356     },
357     /* XmManager class part */
358     {
359         /* translations                 */ XtInheritTranslations,
360         /* syn_resources                */ syn_resources,
361         /* num_syn_resources            */ XtNumber(syn_resources),
362         /* syn_constraint_resources     */ NULL,
363         /* num_syn_constraint_resources */ 0,
364         /* parent_process               */ XmInheritParentProcess,
365         /* extension                    */ (XtPointer)NULL /*&_XmScaleMClassExtRec*/
366     },
367     /* XmScale part */
368     {
369 	/* extension */ NULL,
370     },
371 };
372 
373 
374 
375 WidgetClass xmScaleWidgetClass = (WidgetClass)&xmScaleClassRec;
376 
377 
378 static void
class_initialize(void)379 class_initialize(void)
380 {
381     _XmScaleCoreClassExtRec.record_type = XmQmotif;
382 }
383 
384 
385 static void
class_part_initialize(WidgetClass widget_class)386 class_part_initialize(WidgetClass widget_class)
387 {
388     XmScaleWidgetClass scclass = (XmScaleWidgetClass)widget_class;
389     CompositeClassExtension ext, *extptr;
390 
391     extptr = (CompositeClassExtension *)_XmGetClassExtensionPtr(
392 		    (XmGenericClassExt *)&(scclass->composite_class.extension),
393 								   NULLQUARK);
394 
395     if (extptr == NULL || *extptr == NULL)
396     {
397 	ext = (CompositeClassExtension)XtNew(CompositeClassExtensionRec);
398 	if (ext != NULL)
399 	{
400 	    ext->next_extension = scclass->composite_class.extension;
401 	    ext->record_type = NULLQUARK;
402 	    ext->version = XtCompositeExtensionVersion;
403 	    ext->record_size = sizeof(CompositeClassExtensionRec);
404 	    ext->accepts_objects = True;
405 #if XtSpecificationRelease >= 6
406 	    ext->allows_change_managed_set = True;
407 #endif
408 	    scclass->composite_class.extension = (XtPointer)ext;
409 	}
410     }
411 
412     _XmFastSubclassInit(widget_class, XmSCALE_BIT);
413 }
414 
415 
416 static void
CreateForegroundGC(Widget w)417 CreateForegroundGC(Widget w)
418 {
419     XtGCMask mask;
420     XGCValues values;
421 
422     mask = GCForeground | GCBackground | GCFillStyle | GCFunction | GCFont |
423 	GCSubwindowMode | GCGraphicsExposures | GCPlaneMask;
424     values.function = GXcopy;
425     values.plane_mask = -1;
426     values.subwindow_mode = ClipByChildren;
427     values.graphics_exposures = False;
428     values.foreground = MGR_Foreground(w);
429     values.background = XtBackground(w);
430     values.fill_style = FillSolid;
431     values.font = Scale_FontStruct(w)->fid;
432 
433     Scale_ForegroundGC(w) = XtGetGC(w, mask, &values);
434 }
435 
436 
437 static void
initialize(Widget request,Widget new_w,ArgList args,Cardinal * num_args)438 initialize(Widget request, Widget new_w,
439 	   ArgList args, Cardinal *num_args)
440 {
441     Widget title;
442     Widget sb;
443     Arg argl[15];
444     int argc;
445     /*
446     XmKidGeometry boxes;
447     Dimension wd, ht;
448     */
449 
450     DEBUGOUT(_LtDebug(__FILE__, new_w,
451 		      "%s:initialize(%d) - %i args\n"
452 		      "\trequest X %5i Y %5i W %5i H %5i\n"
453 		      "\t  new_w X %5i Y %5i W %5i H %5i\n",
454 		      __FILE__, __LINE__,
455 		      *num_args,
456 		      XtX(request), XtY(request),
457 		      XtWidth(request), XtHeight(request),
458 		      XtX(new_w), XtY(new_w),
459 		      XtWidth(new_w), XtHeight(new_w)));
460     DEBUGOUT(_LtDebugPrintArgList(__FILE__, new_w, args, *num_args, False));
461 
462     if (Scale_ScaleWidth(new_w) == 0)
463     {
464     	/* rws 22 Dec 1999
465     	   scale/test18 scale/test16
466     	 */
467 	if (Scale_Orientation(new_w) == XmHORIZONTAL)
468 	{
469 	    Scale_ScaleWidth(new_w) = XtWidth(request);
470     	}
471     	else
472 	{
473 	    Scale_ScaleWidth(new_w) = XtHeight(request);
474     	}
475     }
476     if (Scale_Value(new_w) == INT_MAX)
477     {
478 	if (Scale_Minimum(new_w) >= 0)
479 	{
480 	    Scale_Value(new_w) = Scale_Minimum(new_w);
481 	}
482 	else
483 	{
484 	    Scale_Value(new_w) = 0;
485 	}
486     }
487 
488     if (Scale_ScaleMultiple(new_w) == 0)
489     {
490 	Scale_ScaleMultiple(new_w) =
491 	    (Scale_Maximum(new_w) - Scale_Minimum(new_w)) / 10;
492     }
493 
494     Scale_LastValue(new_w) = Scale_Value(new_w);
495 
496 	/* T. Straumann: there is no old value to be erased in showValue() */
497 	Scale_ShowValueX(new_w) = SHOW_VALUE_X_INVALID;
498 
499     if (Scale_FontList(new_w) == NULL)
500     {
501 	Scale_FontList(new_w) = _XmGetDefaultFontList(new_w, XmLABEL_FONTLIST);
502     }
503     /* if user specified fontlist, COPY it */
504     else
505     {
506 	Scale_FontList(new_w) = XmFontListCopy(Scale_FontList(new_w));
507     }
508 
509     /* MLM FIX ME -- Should the titleString get the FontList from the scale? */
510     argc = 0;
511     if (Scale_Title(new_w) != NULL)
512     {
513 	Scale_Title(new_w) = XmStringCopy(Scale_Title(new_w));
514     }
515     XtSetArg(argl[argc], XmNlabelString, Scale_Title(new_w)); argc++;
516     XtSetArg(argl[argc], XmNalignment, XmALIGNMENT_BEGINNING); argc++;
517 
518     title = XmCreateLabelGadget(new_w, "Title", argl, argc);
519     if (Scale_Title(new_w) != NULL)
520     {
521 	XtManageChild(title);
522     }
523 
524     argc = 0;
525     XtSetArg(argl[argc], XmNshowArrows, False); argc++;
526     XtSetArg(argl[argc], XmNtraversalOn, True); argc++;
527     XtSetArg(argl[argc], XmNhighlightOnEnter, True); argc++;
528     XtSetArg(argl[argc], XmNmaximum, SCB_MAX); argc++;
529     XtSetArg(argl[argc], XmNminimum, SCB_MIN); argc++;
530     XtSetArg(argl[argc], XmNorientation, Scale_Orientation(new_w)); argc++;
531     XtSetArg(argl[argc], XmNprocessingDirection,
532 	     Scale_ProcessingDirection(new_w)); argc++;
533     XtSetArg(argl[argc], XmNwidth, Scale_ScaleWidth(new_w)); argc++;
534     XtSetArg(argl[argc], XmNheight, Scale_ScaleHeight(new_w)); argc++;
535     XtSetArg(argl[argc], XmNshadowThickness,
536 	     Scale_ShadowThickness(new_w)); argc++;
537     XtSetArg(argl[argc], XmNhighlightThickness,
538 	     Scale_HighlightThickness(new_w)); argc++;
539     XtSetArg(argl[argc], XmNhighlightOnEnter,
540 	     Scale_HighlightOnEnter(new_w)); argc++;
541 	/* T. Straumann:  M*TIF enforces 0 borderWidth for scrollBar */
542     XtSetArg(argl[argc], XmNborderWidth, 0); argc++;
543 
544     sb = XmCreateScrollBar(new_w, "Scrollbar", argl, argc);
545 
546     _XmSetEtchedSlider((XmScrollBarWidget)sb);
547 
548     XtAddCallback(sb, XmNdragCallback, _ScaleDrag, NULL);
549 
550     if (Scale_Value(new_w) == INT_MAX)
551     {
552 	Scale_Value(new_w) = Scale_Minimum(new_w);
553     }
554 
555     XtAddCallback(sb, XmNvalueChangedCallback, _ScaleValueChanged, NULL);
556     XtManageChild(sb);
557 
558     _XmFontListGetDefaultFont(Scale_FontList(new_w), &Scale_FontStruct(new_w));
559 
560     if (Scale_FontStruct(new_w) == NULL)
561     {
562 	Scale_FontList(new_w) = _XmFontListCreateDefault(XtDisplay(new_w));
563 
564 	_XmFontListGetDefaultFont(Scale_FontList(new_w),
565 				  &Scale_FontStruct(new_w));
566     }
567 
568     CreateForegroundGC(new_w);
569 
570 #if 1
571     { Dimension ht, wd;
572     XmKidGeometry boxes;
573     wd = ht = 0;
574     boxes = _XmScalePreferredSize(new_w, NULL, NULL, &wd, &ht);
575     _XmScaleGeomRequest(new_w, &wd, &ht);
576     _XmScaleLayout(new_w, boxes, NULL, NULL, wd, ht);
577     _XmScaleConfigureChildren(new_w, NULL, boxes);
578     XtFree((char *)boxes);
579     }
580 #endif
581 }
582 
583 
584 static void
destroy(Widget w)585 destroy(Widget w)
586 {
587 
588     if (Scale_Title(w))
589      {
590          XmStringFree(Scale_Title(w));
591      }
592     XmFontListFree(Scale_FontList(w));
593     XtDestroyGC(Scale_ForegroundGC(w));
594 }
595 
596 
597 /*
598  * called when the user changes a resource
599  */
600 /*
601  * FIX ME: changing sensitivity will move value.
602  */
603 static Boolean
set_values(Widget old,Widget request,Widget new_w,ArgList args,Cardinal * num_args)604 set_values(Widget old, Widget request, Widget new_w,
605 	   ArgList args, Cardinal *num_args)
606 {
607     Boolean refresh = False;
608     Arg argl[8];
609     int argc;
610     Widget sb, lab;
611     int resize = False;
612 
613     DEBUGOUT(_LtDebug(__FILE__, new_w, "XmScale set_values()\n"));
614 
615     sb = ((XmScaleWidget)new_w)->composite.children[CHILD_SB];
616     lab = ((XmScaleWidget)new_w)->composite.children[CHILD_LAB];
617 
618     if (Scale_FontList(new_w) &&
619 	Scale_FontList(new_w) != (XmFontList)XmUNSPECIFIED &&
620 	Scale_FontList(new_w) != Scale_FontList(old))
621     {
622 	XmFontListFree(Scale_FontList(old));
623 	Scale_FontList(new_w) = XmFontListCopy(Scale_FontList(new_w));
624     }
625 
626     if (MGR_Foreground(new_w) != MGR_Foreground(old) ||
627 	XtBackground(new_w) != XtBackground(old) ||
628 	Scale_FontList(new_w) != Scale_FontList(old))
629     {
630 	_XmFontListGetDefaultFont(Scale_FontList(new_w),
631 				  &Scale_FontStruct(new_w));
632 
633 	if (Scale_FontStruct(new_w) == NULL)
634 	{
635 	    Scale_FontList(new_w) = _XmFontListCreateDefault(XtDisplay(new_w));
636 
637 	    _XmFontListGetDefaultFont(Scale_FontList(new_w),
638 				      &Scale_FontStruct(new_w));
639 	}
640 
641 	XtReleaseGC(new_w, Scale_ForegroundGC(new_w));
642 	CreateForegroundGC(new_w);
643 
644 	refresh = True;
645     }
646 
647     if (Scale_Title(new_w) != Scale_Title(old))
648     {
649 	if (Scale_Title(old))
650 	{
651 	    XmStringFree(Scale_Title(old));
652 	}
653 
654 	if (Scale_Title(new_w) != NULL)
655 	{
656 	    Scale_Title(new_w) = XmStringCopy(Scale_Title(new_w));
657 
658 	    argc = 0;
659 
660 	    XtSetArg(argl[argc], XmNlabelString, Scale_Title(new_w)); argc++;
661 	    XtSetValues(lab, argl, argc);
662 
663 	    if (!XtIsManaged(lab))
664 	    {
665 	        XtManageChild(lab);
666 	    }
667 	}
668     }
669 
670     if (Scale_Maximum(new_w) != Scale_Maximum(old) ||
671 	Scale_Minimum(new_w) != Scale_Minimum(old) ||
672 	Scale_ProcessingDirection(new_w) != Scale_ProcessingDirection(old) ||
673 	Scale_ScaleMultiple(new_w) != Scale_ScaleMultiple(old) ||
674 	Scale_HighlightOnEnter(new_w) != Scale_HighlightOnEnter(old) ||
675 	Scale_HighlightThickness(new_w) != Scale_HighlightThickness(old) ||
676 	Scale_Value(new_w) != Scale_Value(old))
677     {
678 	int newval;
679 	int inc, page_inc;
680 
681 
682 	newval = _XmScaleConvertScaleValueToSCBValue(new_w);
683 	_XmScaleConvertScaleIncrementToSCBIncrements(new_w, &inc, &page_inc);
684 
685 	argc = 0;
686 	XtSetArg(argl[argc], XmNorientation, Scale_Orientation(new_w)); argc++;
687 	XtSetArg(argl[argc], XmNprocessingDirection,
688 		 Scale_ProcessingDirection(new_w)); argc++;
689 	XtSetArg(argl[argc], XmNvalue, newval); argc++;
690 	XtSetArg(argl[argc], XmNincrement, inc); argc++;
691 	XtSetArg(argl[argc], XmNpageIncrement, page_inc); argc++;
692 	XtSetArg(argl[argc], XmNshadowThickness,
693 		 Scale_ShadowThickness(new_w)); argc++;
694 	XtSetArg(argl[argc], XmNhighlightThickness,
695 		 Scale_HighlightThickness(new_w)); argc++;
696 	XtSetArg(argl[argc], XmNhighlightOnEnter,
697 		 Scale_HighlightOnEnter(new_w)); argc++;
698 	XtSetValues(sb, argl, argc);
699 
700 	refresh = True;
701     }
702 
703     if (Scale_Orientation(new_w) != Scale_Orientation(old))
704 
705     {
706 	argc = 0;
707 	XtSetArg(argl[argc], XmNorientation, Scale_Orientation(new_w)); argc++;
708 
709 	XtSetValues(sb, argl, argc);
710 
711 	/* Surprise, surprise, M*tif doesn't do a relayout here */
712 	resize = False;
713     }
714 
715     if (Scale_ScaleWidth(new_w) != Scale_ScaleWidth(old) ||
716 	Scale_ScaleHeight(new_w) != Scale_ScaleHeight(old))
717     {
718 	argc = 0;
719 	if (Scale_ScaleWidth(new_w) != Scale_ScaleWidth(old) ) {
720 	    XtSetArg(argl[argc], XmNwidth, Scale_ScaleWidth(new_w)); argc++;
721 	}
722 	if ( Scale_ScaleHeight(new_w) != Scale_ScaleHeight(old) ) {
723 	    XtSetArg(argl[argc], XmNheight, Scale_ScaleHeight(new_w)); argc++;
724 	}
725 
726 	XtSetValues(sb, argl, argc);
727 
728 #if 0
729 	resize = False;
730 
731 	/* FIX ME: adapt for new style _XmScaleLayout */
732 	_XmScaleLayout(new_w, resize, NULL, False, NULL);
733 #endif
734 
735 	refresh = True;
736     }
737 
738 	/* T. Straumann: if Scale_ShowValue changed we have to
739 	 * do some more things
740 	 */
741 	if (Scale_ShowValue(new_w) != Scale_ShowValue(old))
742 	{
743 		refresh = True;
744 		if ( ! Scale_ShowValue(new_w) )
745 		{
746 			/* undraw the old value */
747 			if (XtIsRealized(old) && SHOW_VALUE_X_INVALID != Scale_ShowValueX(old))
748 			{
749 				XFillRectangle(XtDisplay(old), XtWindow(old), MGR_BackgroundGC(old),
750 					Scale_ShowValueX(old), Scale_ShowValueY(old),
751 					Scale_ShowValueWidth(old), Scale_ShowValueHeight(old));
752 			}
753 		}
754 		/* Mark Scale_ShowValueX as invalid */
755 		Scale_ShowValueX(new_w) = SHOW_VALUE_X_INVALID;
756 	}
757 
758     if (Scale_Maximum(new_w) != Scale_Maximum(old) ||
759         Scale_Minimum(new_w) != Scale_Minimum(old) ||
760         Scale_DecimalPoints(new_w) != Scale_DecimalPoints(old) ||
761 	Scale_FontList(new_w) != Scale_FontList(old))
762     {
763 	refresh = True;
764 
765         if (Scale_ShowValue(new_w))
766         {
767             computeValueSize(new_w);
768             if (XtIsRealized(old) && SHOW_VALUE_X_INVALID != Scale_ShowValueX(old))
769             {
770                 XFillRectangle(XtDisplay(old), XtWindow(old), MGR_BackgroundGC(old),
771 			Scale_ShowValueX(old), Scale_ShowValueY(old),
772 			Scale_ShowValueWidth(old), Scale_ShowValueHeight(old));
773             }
774             Scale_ShowValueX(new_w) = SHOW_VALUE_X_INVALID;
775         }
776 #if 0
777 	resize = False;
778 
779 	/* FIX ME: adapt for new style _XmScaleLayout */
780 	_XmScaleLayout(new_w, resize, NULL, False, XtWidth(new_w),
781 		       XtHeight(new_w));
782 #endif
783     }
784 
785 #if 0
786     /* dunno about this */
787     XmKidGeometry boxes;
788     Dimension wd, ht;
789 
790     wd = XtWidth(new_w);
791     ht = XtHeight(new_w);
792     boxes = _XmScalePreferredSize(new_w, NULL, NULL, &wd, &ht);
793 
794     _XmScaleGeomRequest(new_w, &wd, &ht);
795     _XmScaleLayout(new_w, boxes, NULL, NULL, wd, ht);
796     _XmScaleConfigureChildren(new_w, NULL, boxes);
797 
798     XtFree((char *)boxes);
799 #endif
800 
801     return refresh;
802 }
803 
804 
805 static void
expose(Widget w,XEvent * event,Region region)806 expose(Widget w,
807        XEvent *event,
808        Region region)
809 {
810     DEBUGOUT(_LtDebug(__FILE__, w, "XmScale expose()\n"));
811 
812     _XmRedisplayGadgets(w, event, region);
813 
814     if (Scale_ShowValue(w))
815     {
816 	showValue(w,
817 		  _XmScaleConvertScaleValueToSCBValue(w),
818 		  Scale_Value(w));
819     }
820 }
821 
822 
823 /*
824  * called when our parent wants to find out how we would like to look.  It
825  * doesn't have to honor our preference, though.
826  */
827 static XtGeometryResult
query_geometry(Widget w,XtWidgetGeometry * request,XtWidgetGeometry * reply)828 query_geometry(Widget w, XtWidgetGeometry *request, XtWidgetGeometry *reply)
829 {
830 #if 0
831     XtWidgetGeometry wants;
832     XmKidGeometry boxes;
833     Dimension wd, ht;
834 
835 #define Wants(x)	((wants.request_mode & x) == x)
836 
837     DEBUGOUT(_LtDebug(__FILE__, w, "XmScale %s QueryGeometry\n", XtName(w)));
838 
839     wants = *request;
840     *reply = *request;
841     reply->request_mode = 0;
842 
843     if (Wants(CWWidth))
844     {
845 	reply->request_mode |= CWWidth;
846 	reply->width = XtWidth(w);
847     }
848 
849     if (Wants(CWHeight))
850     {
851 	reply->request_mode |= CWHeight;
852 	reply->height = XtHeight(w);
853     }
854 
855     boxes = _XmScalePreferredSize(w, NULL, NULL, &wd, &ht);
856 
857     reply->width = wd;
858     reply->height = ht;
859 
860     if (Wants(CWHeight) && (wants.height < reply->height))
861     {
862 	return XtGeometryNo;
863     }
864     else if (Wants(CWHeight) && (wants.height > reply->height))
865     {
866 	return XtGeometryAlmost;
867     }
868 
869     if (Wants(CWWidth) && (wants.width < reply->width))
870     {
871 	return XtGeometryNo;
872     }
873     else if (Wants(CWWidth) && (wants.width > reply->width))
874     {
875 	return XtGeometryAlmost;
876     }
877 
878     return XtGeometryYes;
879 
880 #undef Wants
881 #else
882     XtWidgetGeometry wants;
883     Dimension wd, ht;
884 
885     DEBUGOUT(_LtDebug(__FILE__, w, "XmScale %s QueryGeometry\n", XtName(w)));
886 
887     wants = *request;
888 
889     _XmScalePreferredSize(w, NULL, NULL, &wd, &ht);
890 
891     reply->width = wd;
892     reply->height = ht;
893 
894     return _XmGMReplyToQueryGeometry(w, &wants, reply);
895 #endif
896 }
897 
898 
899 /*
900  * called when our parent is resizing us.  We have no choice but to obey.
901  */
902 static void
resize(Widget w)903 resize(Widget w)
904 {
905     XmKidGeometry boxes;
906     Dimension wd, ht;
907 
908     DEBUGOUT(_LtDebug(__FILE__, w, "Scale %s Resize: x %d y %d w %d h %d\n",
909 		      XtName(w), XtX(w), XtY(w), XtWidth(w), XtHeight(w)));
910 
911     Scale_SliderSize(w) = _XmScaleConvertWidthToSliderSize(w);
912 
913     wd = XtWidth(w);
914     ht = XtHeight(w);
915     boxes = _XmScalePreferredSize(w, NULL, NULL, &wd, &ht);
916 
917     _XmScaleLayout(w, boxes, NULL, NULL, wd, ht);
918 
919     _XmScaleConfigureChildren(w, NULL, boxes);
920 
921     XtFree((char *)boxes);
922 }
923 
924 
925 /*
926  * called when one of our children wants to change.  We control whether
927  * the child can, or not
928  * Note that the scrolbar can't change it's size.
929  */
930 #define       Wants(x)        (wants.request_mode & x)
931 static XtGeometryResult
geometry_manager(Widget w,XtWidgetGeometry * request,XtWidgetGeometry * reply)932 geometry_manager(Widget w, XtWidgetGeometry *request, XtWidgetGeometry *reply)
933 {
934     Dimension wd, ht;
935     XmKidGeometry boxes;
936     XtWidgetGeometry wants;
937 
938     DEBUGOUT(_LtDebug(__FILE__, w, "XmScale geometry_manager()\n"));
939 
940     wants = *request;
941 
942     if ((Wants(CWX) /* FIX ME: && request->x != XtX(w) */ ) ||
943 	(Wants(CWY) /* FIX ME: && request->y != XtY(w) */ ))
944     {
945 	return XtGeometryNo;
946     }
947 
948     /* FIX ME: Should XtCWQueryOnly be handled at all? */
949     if (Wants(XtCWQueryOnly))
950     {
951 	_XmWarning(XtParent(w),
952 		   "FIX ME: XtCWQueryOnly not handled (child %s)\n",
953 		   XtName(w));
954     }
955 
956     boxes = _XmScalePreferredSize(XtParent(w), w, request, &wd, &ht);
957 
958     _XmScaleGeomRequest(XtParent(w), &wd, &ht);
959 
960     *reply = *request;
961     reply->request_mode &= CWWidth|CWHeight;
962 
963     if (Wants(CWWidth) && Wants(CWHeight) &&
964 	wants.width == reply->width && wants.height == reply->height)
965     {
966 	_XmScaleConfigureChildren(XtParent(w), w, boxes);
967 
968 	return XtGeometryYes;
969     }
970 
971     if (Wants(CWWidth) && wants.width == reply->width)
972     {
973 	_XmScaleConfigureChildren(XtParent(w), w, boxes);
974 
975 	return XtGeometryYes;
976     }
977 
978     if (Wants(CWHeight) && wants.height == reply->height)
979     {
980 	_XmScaleConfigureChildren(XtParent(w), w, boxes);
981 
982 	return XtGeometryYes;
983     }
984 
985     if (Wants(CWWidth) && wants.width == reply->width)
986     {
987     	reply->request_mode &= ~CWWidth;
988     }
989     if (Wants(CWHeight) && wants.height == reply->height)
990     {
991     	reply->request_mode &= ~CWHeight;
992     }
993     return XtGeometryAlmost;
994 #undef Wants
995 }
996 
997 
998 /*
999  * called when our Window is allocated.  We may want to change our layout,
1000  * and we can ask our parent to allow this
1001  */
1002 static void
realize(Widget w,XtValueMask * value_mask,XSetWindowAttributes * attributes)1003 realize(Widget w, XtValueMask *value_mask, XSetWindowAttributes *attributes)
1004 {
1005     /*
1006     Dimension wd, ht;
1007     Dimension pwd, pht;
1008     XmKidGeometry boxes;
1009     */
1010 
1011     DEBUGOUT(_LtDebug(__FILE__, w, "XmScale realize()\n"));
1012 
1013 #define superclass (&xmManagerClassRec)
1014     (*superclass->core_class.realize) (w, value_mask, attributes);
1015 #undef superclass
1016 
1017 #if 0
1018     wd = ht = 0;
1019     boxes = _XmScalePreferredSize(w, NULL, NULL, &wd, &ht);
1020     pwd = wd;
1021     pht = ht;
1022 
1023     _XmScaleGeomRequest(w, &wd, &ht);
1024     _XmScaleLayout(w, boxes, NULL, NULL, pwd, pht);
1025     _XmScaleConfigureChildren(w, NULL, boxes);
1026 
1027     XtFree((char *)boxes);
1028 #endif
1029 }
1030 
1031 
1032 /*
1033  * one of our children has become managed or unmanaged.  We need to relayout
1034  */
1035 static void
change_managed(Widget w)1036 change_managed(Widget w)
1037 {
1038     Dimension wd, ht;
1039     XmKidGeometry boxes;
1040 
1041     DEBUGOUT(_LtDebug(__FILE__, w, "XmScale change_managed()\n"));
1042 
1043     wd = ht = 0;
1044     boxes = _XmScalePreferredSize(w, NULL, NULL, &wd, &ht);
1045 
1046     _XmScaleGeomRequest(w, &wd, &ht);
1047 
1048     _XmScaleLayout(w, boxes, NULL, NULL, wd, ht);
1049 
1050     _XmScaleConfigureChildren(w, NULL, boxes);
1051 
1052     XtFree((char *)boxes);
1053 
1054     _XmNavigChangeManaged(w);
1055 }
1056 
1057 
1058 #if 0
1059 /*
1060  * a child has been added
1061  */
1062 static void
1063 insert_child(Widget w)
1064 {
1065 #define superclass      (&xmManagerClassRec)
1066     (*superclass->composite_class.insert_child) (w);
1067 #undef  superclass
1068 
1069     DEBUGOUT(_LtDebug(__FILE__, w,
1070 		      "Scale %s: insert child %s\n",
1071 		      XtName(XtParent(w)), XtName(w)));
1072 }
1073 #endif
1074 
1075 
1076 extern Widget
XmCreateScale(Widget parent,char * name,Arg * arglist,Cardinal argcount)1077 XmCreateScale(Widget parent,
1078 	      char *name,
1079 	      Arg *arglist,
1080 	      Cardinal argcount)
1081 {
1082     return XtCreateWidget(name,
1083 			  xmScaleWidgetClass,
1084 			  parent,
1085 			  arglist,
1086 			  argcount);
1087 }
1088 
1089 
1090 extern void
XmScaleGetValue(Widget widget,int * value_return)1091 XmScaleGetValue(Widget widget,
1092 		int *value_return)
1093 {
1094     *value_return = Scale_Value(widget);
1095 }
1096 
1097 
1098 extern void
XmScaleSetValue(Widget widget,int value)1099 XmScaleSetValue(Widget widget,
1100 		int value)
1101 {
1102     Widget sb;
1103     int newval;
1104 
1105     sb = ((XmScaleWidget)widget)->composite.children[CHILD_SB];
1106 
1107     if (value < Scale_Minimum(widget) || value > Scale_Maximum(widget))
1108     {
1109 	return;
1110     }
1111 
1112     Scale_Value(widget) = value;
1113     newval = _XmScaleConvertScaleValueToSCBValue(widget);
1114 
1115     XtVaSetValues((Widget)sb,
1116 		  XmNvalue, newval,
1117 		  NULL);
1118 
1119     if (Scale_ShowValue(widget))
1120     {
1121 	showValue(widget, newval, Scale_Value(widget));
1122     }
1123 }
1124 
1125 
1126 static void
valueToString(Widget w,char * buf)1127 valueToString(Widget w, char *buf)
1128 {
1129     int base, i;
1130     char buf2[17];		/* anybody got larger than 64 bit ints? */
1131 
1132     if (Scale_DecimalPoints(w) <= 0)
1133     {
1134 	sprintf(buf, "%d", Scale_Value(w));
1135     }
1136     else
1137     {
1138 	/* I'd like to use %d.%*d here, but not everyone has that */
1139 	base = 10;
1140 	for (i = 1; i < Scale_DecimalPoints(w); i++)
1141 	{
1142 	    base *= 10;
1143 	}
1144 
1145 #if 0
1146 	sprintf(buf, "%d.", Scale_Value(w) / base);
1147 #else
1148 	sprintf(buf, "%s%d.", Scale_Value(w) >= 0 ? "" : "-",
1149 		abs(Scale_Value(w) / base));
1150 #endif
1151 	for (i = 1; i <= Scale_DecimalPoints(w); i++)
1152 	{
1153 	    strcat(buf, "0");
1154 	}
1155 
1156 #if 0
1157 	sprintf(buf2, "%d", Scale_Value(w) % base);
1158 #else
1159 	sprintf(buf2, "%d", abs(Scale_Value(w) % base));
1160 #endif
1161 	strcpy(&buf[strlen(buf) - strlen(buf2)], buf2);
1162     }
1163 }
1164 
1165 /*
1166  * layout rules
1167  *
1168  * scrollbar stays at rightmost or bottommost position, when no label
1169  * ScaleWidth/ScaleHeight are hints.  If it is set, pay attention to it;
1170  * otherwise, obey the parent.
1171  *
1172  * FIX ME - currently, we always allow a widget to resize.
1173  *
1174  * FIX ME: signs are some of the XtIsManaged tests will have to go.
1175  *
1176  * FIX ME: if scaleWidth/Height is specified  scrollbar_width/height can
1177  * get arbitrary small. If width/height is specified slider_width/height
1178  * is bound to a minimum.
1179  *
1180  * FIX ME:
1181  * Srollbar should not go off the scale by wide tick marks.
1182  * Children's initial geometry not respected.
1183  *
1184  * FIX ME: tick mark x/y seems to have a minimum value of -4
1185  *
1186  * layout is normal processing as per the M*tif docs
1187  * (Hmm.. tick marks and title get laid out on opposite sides of SB -- PvH)
1188  *  per me, this is as follows (FIX ME -- this is not complete):
1189  *    if (orientation is HORIZONTAL) then
1190  *      layout title (if managed), and other children (if present)
1191  *        along the bottom edge.  This initially defines our preferred
1192  *        width, and the tallest child defines the slider's bottom edge.
1193  *        if (TestMode) then
1194  *          if the child widget argument is the same as the current child
1195  *             and the geometry request is a match for the calculated
1196  *             geometry, the return XtGeometryYes.
1197  *          else
1198  *             return XtGeometryNo
1199  *          endif
1200  *        endif
1201  *      layout the slider above the tallest managed child other than the
1202  *        scrollbar (if any).
1203  *        if (ScaleHeight hint is set) then
1204  *          we must use that as the slider height
1205  *        else
1206  *          use the default slider height
1207  *        endif
1208  *        if (ScaleWidth hint is set)
1209  *          we must use it as the slider width
1210  *        else
1211  *          use our width as the slider width
1212  *        endif
1213  *        if (TestMode) then
1214  *          if the child widget argument is the same as the current child
1215  *             and the geometry request is a match for the calculated
1216  *             geometry, the return XtGeometryYes.
1217  *          else
1218  *             return XtGeometryNo
1219  *          endif
1220  *        endif
1221  *        layout the value (if ShowValue is true) to be from the top of the
1222  *          slider. The value should not affect the width calculation.
1223  *    else if (orientation is VERTICAL) then
1224  *      layout title (if managed), and other children (if present)
1225  *        along the right edge.  This initially defines our preferred
1226  *        height, and the tallest child defines the slider's right edge.
1227  *        if (TestMode) then
1228  *          if the child widget argument is the same as the current child
1229  *             and the geometry request is a match for the calculated
1230  *             geometry, the return XtGeometryYes.
1231  *          else
1232  *             return XtGeometryNo
1233  *          endif
1234  *        endif
1235  *      layout the slider left of the tallest managed child other than the
1236  *        scrollbar (if any).
1237  *        if (ScaleWidth hint is set) then
1238  *          we must use that as the slider width
1239  *        else
1240  *          use the default slider width
1241  *        endif
1242  *        if (ScaleHeight hint is set)
1243  *          we must use it as the slider height
1244  *        else
1245  *          use our height as the slider height
1246  *        endif
1247  *        if (TestMode) then
1248  *          if the child widget argument is the same as the current child
1249  *             and the geometry request is a match for the calculated
1250  *             geometry, the return XtGeometryYes.
1251  *          else
1252  *             return XtGeometryNo
1253  *          endif
1254  *        endif
1255  *      layout the value (if ShowValue is true) to be from the right of the
1256  *        slider. The value should not affect the height calculation.
1257  *    endif
1258  *
1259  *    we have now computed our preferred width and height, or returned.
1260  *    if (ParentResizeMode) then
1261  *      do
1262  *        request size change
1263  *      while (change not allowed, but close)
1264  *      our width = new width
1265  *      our height = new height
1266  *    else
1267  *      our width = XtWidth
1268  *      our height = XtHeight
1269  *    endif
1270  *
1271  *    if (our width < preferred width) then
1272  *      compute layouts that maximize the display of the scrollbar and
1273  *      the value (if ShowValue is true)
1274  *    else
1275  *      compute proportional layouts
1276  *    endif
1277  *    if (our height < preferred height) then
1278  *      compute layouts that maximize the display of the scrollbar and
1279  *      the value (if ShowValue is true)
1280  *    else
1281  *      compute proportional layouts
1282  *    endif
1283  *
1284  *    for each widget
1285  *      XmConfigureWidget
1286  *    endfor
1287  *
1288  *  end algorithm
1289  *
1290  * My additions:
1291  * never allow a child to request an XY change. (is this correct?)
1292  * the ScrollBar shall always be children[1]
1293  * the LabelGadget shall always be children[0]
1294  * This is per M*tif!
1295  */
1296 static XmKidGeometry
_XmScalePreferredSize(Widget scale,Widget child,XtWidgetGeometry * childgeom,Dimension * wd,Dimension * ht)1297 _XmScalePreferredSize(Widget scale, Widget child, XtWidgetGeometry *childgeom,
1298 		      Dimension *wd, Dimension *ht)
1299 {
1300     Position curx, cury;
1301     XmKidGeometry boxes;
1302     Dimension curw, curh;
1303     Dimension incw, inch;
1304     int maxw, maxh;
1305     Widget *children;
1306     int num_children;
1307     int i, cnt;
1308 
1309     curx = cury = 0;
1310     curw = curh = 0;
1311     incw = inch = 0;
1312     maxw = maxh = 0;
1313 
1314     num_children = MGR_NumChildren(scale);
1315     children = MGR_Children(scale);
1316 
1317     boxes = (XmKidGeometry)XtCalloc(num_children + 1, sizeof(XmKidGeometryRec));
1318 
1319     boxes[CHILD_SB].kid = children[CHILD_SB];
1320     if (children[CHILD_SB])
1321     {
1322 	_XmGeoLoadValues(children[CHILD_SB], XmGET_PREFERRED_SIZE,
1323 			 child, childgeom, &boxes[CHILD_SB].box);
1324     }
1325 
1326     boxes[CHILD_LAB].kid = children[CHILD_LAB];
1327     if (children[CHILD_LAB])
1328     {
1329 	_XmGeoLoadValues(children[CHILD_LAB], XmGET_PREFERRED_SIZE,
1330 			 child, childgeom, &boxes[CHILD_LAB].box);
1331     }
1332 
1333     for (i = 2, cnt = 2; i < num_children; i++)
1334     {
1335 	if (XtIsManaged(children[i]))
1336 	{
1337 	    boxes[cnt].kid = children[i];
1338 
1339 	    _XmGeoLoadValues(children[i], XmGET_PREFERRED_SIZE,
1340 			     child, childgeom, &boxes[cnt].box);
1341 
1342 	    if (maxw < boxes[cnt].box.width)
1343 	    {
1344 		maxw = boxes[cnt].box.width;
1345 	    }
1346 	    if (maxh < boxes[cnt].box.height)
1347 	    {
1348 		maxh = boxes[cnt].box.height;
1349 	    }
1350 
1351 	    cnt++;
1352 	}
1353 	else
1354 	{
1355 	    boxes[i].kid = NULL;
1356 	}
1357     }
1358 
1359     boxes[i].kid = NULL;
1360 
1361     num_children = cnt;
1362 
1363     /*
1364      * compute it.
1365      */
1366     if (Scale_Orientation(scale) == XmHORIZONTAL)
1367     {
1368 
1369 	curh = maxh;
1370 	cury = maxh;
1371 
1372 	/*
1373 	 * do the value, if there is one
1374 	 */
1375 	if (Scale_ShowValue(scale))
1376 	{
1377 
1378 	    computeValueSize(scale);
1379 
1380 	    incw = Scale_ShowValueWidth(scale);
1381 	    inch = Scale_ShowValueHeight(scale);
1382 
1383 	    if (incw > curw)
1384 	    {
1385 		curw = incw;
1386 	    }
1387 	    curh += inch;
1388 
1389 	    cury += inch;
1390 	}
1391 
1392 	/*
1393 	 * then do the ScrollBar
1394 	 */
1395 	if (XtIsManaged(boxes[CHILD_SB].kid))
1396 	{
1397 
1398 	    boxes[CHILD_SB].box.x = curx;
1399 	    boxes[CHILD_SB].box.y = cury;
1400 
1401 	    inch = Scale_ScaleHeight(scale);
1402 
1403 	    if (inch == 0)
1404 	    {
1405 		inch = SB_TRANSVERSAL_SIZE +
1406 		    2 * Scale_HighlightThickness(scale);
1407 	    }
1408 
1409 	    incw = Scale_ScaleWidth(scale);
1410 
1411 	    if (incw == 0)
1412 	    {
1413 		incw = XtWidth(scale);
1414 	    }
1415 
1416 #if 0
1417 	    if (incw == 0 && num_children >= 3)
1418 #else
1419 	    if (Scale_ScaleWidth(scale) == 0 && num_children >= 3)
1420 #endif
1421 	    {
1422 		if (num_children == 3)
1423 		{
1424 		    incw = boxes[2].box.width;
1425 		}
1426 		else
1427 		{
1428 		    incw = HSLIDERSIZE +
1429 			2 * (Prim_HighlightThickness(boxes[CHILD_SB].kid) +
1430 			     Prim_ShadowThickness(boxes[CHILD_SB].kid)) +
1431 			maxw * (num_children - 3);
1432 		}
1433 	    }
1434 
1435 	    if (incw == 0)
1436 	    {
1437 		incw = SB_LONGITUDAL_SIZE + 2 * Scale_HighlightThickness(scale);
1438 	    }
1439 
1440 	    boxes[CHILD_SB].box.width = incw;
1441 	    boxes[CHILD_SB].box.height = inch;
1442 
1443 	    if (incw > curw)
1444 	    {
1445 		curw = incw;
1446 	    }
1447 
1448 	    curh += inch;
1449 	    cury += inch;
1450 	}
1451 
1452 	/* lay out the tick marks */
1453 	if (num_children > 2)
1454 	{
1455 	    /* centres are nicely aligned */
1456 
1457 	    if (num_children > 3)
1458 	    {
1459 		int spacing;
1460 
1461 		if (curw == 0)
1462 		{
1463 		    spacing = maxw * (num_children - 3);
1464 		}
1465 		else
1466 		{
1467 		    spacing = (curw -
1468 			       (HSLIDERSIZE +
1469 			     2 * (Prim_HighlightThickness(boxes[CHILD_SB].kid) +
1470 				  Prim_ShadowThickness(boxes[CHILD_SB].kid))));
1471 		}
1472 
1473 		for (i = 2; i < num_children; i++)
1474 		{
1475 		    boxes[i].box.y = (maxh - boxes[i].box.height) / 2;
1476 		    boxes[i].box.x = (HSLIDERSIZE - boxes[i].box.width) / 2 +
1477 			    Prim_HighlightThickness(boxes[CHILD_SB].kid) +
1478 			    Prim_ShadowThickness(boxes[CHILD_SB].kid) +
1479 			    (i - 2) * spacing / (num_children - 3);
1480 		}
1481 	    }
1482 	    else
1483 	    {
1484 		boxes[2].box.y = 0;
1485 		boxes[2].box.x = (curw - boxes[2].box.width) / 2;
1486 	    }
1487 	}
1488 
1489 	/*
1490 	 * then the title, if there is one
1491 	 */
1492 	if (Scale_Title(scale) && XtIsManaged(boxes[CHILD_LAB].kid))
1493 	{
1494 	    boxes[CHILD_LAB].box.x = curx;
1495 	    boxes[CHILD_LAB].box.y = cury;
1496 
1497 	    incw = boxes[CHILD_LAB].box.width;
1498 	    inch = boxes[CHILD_LAB].box.height;
1499 
1500 	    if (incw > curw)
1501 	    {
1502 		curw = incw;
1503 	    }
1504 	    curh += inch;
1505 
1506 	    curx += incw;
1507 	    curh += 2 * MGR_ShadowThickness(scale);
1508 	}
1509     }
1510     /* XmNorientation == XmVERTICAL */
1511     else
1512     {
1513 
1514 	curw = maxw;
1515 	curx = maxw;
1516 
1517 	/*
1518 	 * do the value, if there is one
1519 	 */
1520 	if (Scale_ShowValue(scale))
1521 	{
1522 
1523 	    computeValueSize(scale);
1524 
1525 	    inch = Scale_ShowValueHeight(scale);
1526 	    incw = Scale_ShowValueWidth(scale);
1527 
1528 	    if (inch > curh)
1529 	    {
1530 		curh = inch;
1531 	    }
1532 
1533 	    curw += incw;
1534 
1535 	    curx += incw;
1536 	}
1537 
1538 	/*
1539 	 * then do the ScrollBar
1540 	 */
1541 	if (XtIsManaged(boxes[CHILD_SB].kid))
1542 	{
1543 	    boxes[CHILD_SB].box.x = curx;
1544 	    boxes[CHILD_SB].box.y = cury;
1545 
1546 	    incw = Scale_ScaleWidth(scale);
1547 
1548 	    if (incw == 0)
1549 	    {
1550 		incw = SB_TRANSVERSAL_SIZE +
1551 		    2 * Scale_HighlightThickness(scale);
1552 	    }
1553 
1554 	    inch = Scale_ScaleHeight(scale);
1555 
1556 	    if (inch == 0)
1557 	    {
1558 		inch = XtHeight(scale);
1559 	    }
1560 
1561 #if 0
1562 	    if (inch == 0 && num_children >= 3)
1563 #else
1564 	    if (Scale_ScaleHeight(scale) == 0 && num_children >= 3)
1565 #endif
1566 	    {
1567 		if (num_children == 3)
1568 		{
1569 		    inch = boxes[2].box.height;
1570 		}
1571 		else
1572 		{
1573 		    /* FIX ME: SrollBar's or Scale's? */
1574 		    inch = HSLIDERSIZE +
1575 			2 * (Prim_HighlightThickness(boxes[CHILD_SB].kid) +
1576 			     Prim_ShadowThickness(boxes[CHILD_SB].kid)) +
1577 			maxh * (num_children - 3);
1578 		}
1579 	    }
1580 
1581 	    if (inch == 0)
1582 	    {
1583 		inch = SB_LONGITUDAL_SIZE + 2 * Scale_HighlightThickness(scale);
1584 	    }
1585 
1586 	    boxes[CHILD_SB].box.width = incw;
1587 	    boxes[CHILD_SB].box.height = inch;
1588 
1589 	    if (inch > curh)
1590 	    {
1591 		curh = inch;
1592 	    }
1593 
1594 	    curw += incw;
1595 	    curx += incw;
1596 	}
1597 
1598 	/* lay out the tick marks */
1599 	if (num_children > 2)
1600 	{
1601 	    /* centres are nicely aligned */
1602 
1603 	    if (num_children > 3)
1604 	    {
1605 		int spacing;
1606 
1607 		if (curh == 0)
1608 		{
1609 		    spacing = maxh * (num_children - 3);
1610 		}
1611 		else
1612 		{
1613 		    spacing = (curh - (HSLIDERSIZE +
1614 			     2 * (Prim_HighlightThickness(boxes[CHILD_SB].kid) +
1615 				  Prim_ShadowThickness(boxes[CHILD_SB].kid))));
1616 		}
1617 		printf("curh %i %i %i %i %i %i %i\n",
1618 			spacing,
1619 			curh,
1620 			HSLIDERSIZE,
1621 			maxh,
1622 			num_children,
1623 			Prim_HighlightThickness(boxes[CHILD_SB].kid),
1624 			Prim_ShadowThickness(boxes[CHILD_SB].kid));
1625 
1626 		for (i = 2; i < num_children; i++)
1627 		{
1628 		    boxes[i].box.x = (maxw - boxes[i].box.width) / 2;
1629 		    boxes[i].box.y = 1 + (HSLIDERSIZE - boxes[i].box.height) / 2 +
1630 			    Prim_HighlightThickness(boxes[CHILD_SB].kid) +
1631 			    Prim_ShadowThickness(boxes[CHILD_SB].kid) +
1632 			    (i - 2) * spacing / (num_children - 3);
1633 		}
1634 #if 1
1635 		/* scale/test13 ???? */
1636 		curh++;
1637 		boxes[CHILD_SB].box.height++;
1638 #endif
1639 	    }
1640 	    else
1641 	    {
1642 		boxes[2].box.x = 0;
1643 		boxes[2].box.y = (curh - boxes[2].box.height) / 2;
1644 	    }
1645 	}
1646 
1647 	/*
1648 	 * then the title, if there is one
1649 	 */
1650 	if (Scale_Title(scale) && XtIsManaged(boxes[CHILD_LAB].kid))
1651 	{
1652 
1653 	    boxes[CHILD_LAB].box.x = curx;
1654 	    boxes[CHILD_LAB].box.y = cury;
1655 
1656 
1657 	    incw = boxes[CHILD_LAB].box.width;
1658 	    inch = boxes[CHILD_LAB].box.height;
1659 
1660 	    if (inch > curh)
1661 	    {
1662 		curh = inch;
1663 	    }
1664 
1665 	    curw += incw;
1666 	    cury += inch;
1667 	    curw += 2 * MGR_ShadowThickness(scale);
1668 /*
1669 printf("COMPUTED %d %d : %d %d\n", curw, cury, incw, inch);
1670 */
1671 	}
1672     }
1673 
1674     /*
1675      * if we're being queried for our geometry, return what we've got
1676      */
1677     *wd = curw;
1678     *ht = curh;
1679 
1680     return boxes;
1681 }
1682 
1683 
1684 /*
1685  * if we can, change our size to match
1686  */
1687 static XtGeometryResult
_XmScaleGeomRequest(Widget scale,Dimension * wd,Dimension * ht)1688 _XmScaleGeomRequest(Widget scale, Dimension *wd, Dimension *ht)
1689 {
1690     XtWidgetGeometry request;
1691     XtGeometryResult result;
1692 
1693     request.request_mode = (CWWidth | CWHeight);
1694     request.width = *wd;
1695     request.height = *ht;
1696 
1697     DEBUGOUT(_LtDebug(__FILE__, scale, "_XmScaleGeomRequest(ing) (%d %d)\n",
1698 		      *wd, *ht));
1699 
1700     result = _XmMakeGeometryRequest(scale, &request);
1701 
1702     if (result == XtGeometryYes)
1703     {
1704 	*wd = request.width;
1705 	*ht = request.height;
1706     }
1707     else
1708     {
1709 	*wd = XtWidth(scale);
1710 	*ht = XtHeight(scale);
1711     }
1712 
1713     DEBUGOUT(_LtDebug(__FILE__, scale, "_XmScaleLayout (%d %d) => %s\n",
1714 		      *wd, *ht, _LtDebugGeometryResult2String(result)));
1715 
1716     return result;
1717 }
1718 
1719 
1720 static void
_XmScaleLayout(Widget scale,XmKidGeometry boxes,Widget child,XtWidgetGeometry * childgeom,Dimension curw,Dimension curh)1721 _XmScaleLayout(Widget scale, XmKidGeometry boxes,
1722 	       Widget child, XtWidgetGeometry *childgeom,
1723 	       Dimension curw, Dimension curh)
1724 {
1725     int i, delta;
1726 
1727 	int num_children = MGR_NumChildren(scale);
1728     /*
1729      * do the layout
1730      */
1731     if (Scale_Orientation(scale) == XmHORIZONTAL)
1732     {
1733 #if 0
1734 	if (Scale_ScaleWidth(scale) == 0)
1735 	    boxes[CHILD_SB].box.width = XtWidth(scale);
1736 
1737 	if (boxes[CHILD_SB].box.width < (HSLIDERSIZE + MIN_SLIDE +
1738 				 2 * Prim_ShadowThickness(children[CHILD_SB]) +
1739 				 2 * Scale_HighlightThickness(scale)))
1740 	{
1741 	    boxes[CHILD_SB].box.width = (HSLIDERSIZE + MIN_SLIDE +
1742 				 2 * Prim_ShadowThickness(children[CHILD_SB]) +
1743 				 2 * Scale_HighlightThickness(scale));
1744 	    boxes[CHILD_SB].box.x = (XtWidth(scale) -
1745 		boxes[CHILD_SB].box.width) / 2;
1746 	}
1747 
1748 	if (num_children == 2)
1749 	{
1750 	    boxes[CHILD_LAB].box.width = boxes[CHILD_SB].box.width;
1751 	    boxes[CHILD_LAB].box.x = boxes[CHILD_SB].box.x;
1752 	}
1753 
1754 	if (XtHeight(scale) < (boxes[CHILD_SB].box.y + VSLIDERSIZE +
1755 			       2 * Prim_ShadowThickness(children[CHILD_SB]) +
1756 			       2 * Scale_HighlightThickness(scale)))
1757 	{
1758 	    boxes[CHILD_SB].box.y -= (boxes[CHILD_SB].box.y + VSLIDERSIZE +
1759 				  2 * Prim_ShadowThickness(children[CHILD_SB]) +
1760 				  2 * Scale_HighlightThickness(scale)) -
1761 		XtHeight(scale) + 1;
1762 	}
1763 
1764 	if (XtWidth(scale) > curw)
1765 	{
1766 	    for (i = 2; i < num_children; i++)
1767 	    {
1768 		boxes[i].box.width = (Dimension)((double)boxes[i].box.width /
1769 						 (double)curw *
1770 						 (double)XtWidth(scale));
1771 	    }
1772 	}
1773 #endif /* 0 */
1774 
1775 	if ((delta = XtHeight(scale) - curh))
1776 	{
1777 	    if (delta < 0 && XtIsManaged(boxes[CHILD_LAB].kid))
1778 	    {
1779 		delta += boxes[CHILD_LAB].box.height +
1780 		    (MGR_ShadowThickness(scale) << 1);
1781 		if (delta > 0)
1782 		    delta = 0;
1783 	    }
1784 	    for (i = 0; i < 2 && boxes[i].kid; i++)
1785 	    {
1786 		boxes[i].box.y += delta;
1787 	    }
1788 	}
1789 
1790 	/* T. Straumann: adjust width / tickmark positions if our geometry
1791 	 * is different from the one used in _XmScalePreferredSize().
1792 	 *
1793 	 * They do this only if Scale_ScaleWidth() == 0 or delta < 0
1794 	 * as can be confirmed by test14. Try also to resize
1795 	 *
1796 	 *   test13 -xrm "*scaleHeight:200"
1797 	 *
1798 	 * using the WM
1799 	 */
1800 	delta = XtWidth(scale) - curw;
1801 	if ( delta < 0 || (delta > 0 && 0 == Scale_ScaleWidth(scale) ) )
1802 	{
1803 		/* different layout whether one or more tick marks are present */
1804 		int denom = (num_children == 3 ? 2 : num_children -3);
1805 		for (i = 0; boxes[i].kid; i++)
1806 		{
1807 			switch (i)
1808 			{
1809 				/* adjust the width of SB and LAB */
1810 				case CHILD_LAB:
1811 				case CHILD_SB:
1812 					boxes[i].box.width = XtWidth(scale);
1813 				break;
1814 
1815 				/* adjust the tick marks */
1816 
1817 				default:
1818 					boxes[i].box.x += delta * (i - 2) / denom;
1819 				break;
1820 			}
1821 		}
1822 	}
1823 
1824     }
1825     else if (Scale_Orientation(scale) == XmVERTICAL)
1826     {
1827 #if 0
1828 	if (Scale_ScaleHeight(scale) == 0)
1829 	    boxes[CHILD_SB].box.height = XtHeight(scale);
1830 
1831 	if (boxes[CHILD_SB].box.height < (HSLIDERSIZE + MIN_SLIDE +
1832 				 2 * Prim_ShadowThickness(children[CHILD_SB]) +
1833 				 2 * Scale_HighlightThickness(scale)))
1834 	{
1835 	    boxes[CHILD_SB].box.height = (HSLIDERSIZE + MIN_SLIDE +
1836 				 2 * Prim_ShadowThickness(children[CHILD_SB]) +
1837 				 2 * Scale_HighlightThickness(scale));
1838 	    boxes[CHILD_SB].box.y = (XtHeight(scale) -
1839 		boxes[CHILD_SB].box.height) / 2;
1840 	}
1841 
1842 	if (num_children == 2)
1843 	{
1844 	    boxes[CHILD_LAB].box.height = boxes[CHILD_SB].box.height;
1845 	    boxes[CHILD_LAB].box.y = boxes[CHILD_SB].box.y;
1846 	}
1847 
1848 	if (XtWidth(scale) < (boxes[CHILD_SB].box.width + VSLIDERSIZE +
1849 			      2 * Prim_ShadowThickness(children[CHILD_SB]) +
1850 			      2 * Scale_HighlightThickness(scale)))
1851 	{
1852 	    boxes[CHILD_SB].box.x -= (boxes[CHILD_SB].box.x + VSLIDERSIZE +
1853 				  2 * Prim_ShadowThickness(children[CHILD_SB]) +
1854 				  2 * Scale_HighlightThickness(scale)) -
1855 		XtWidth(scale) + 1;
1856 	}
1857 
1858 	if (XtWidth(scale) > curw)
1859 	{
1860 	    for (i = 2; i < num_children; i++)
1861 		boxes[i].box.height = (Dimension)((double)boxes[i].box.height /
1862 						  (double)curw *
1863 						  (double)XtWidth(scale));
1864 	}
1865 #endif /* 0 */
1866 
1867 	if ((delta = XtWidth(scale) - curw))
1868 	{
1869 	    if (delta < 0 && XtIsManaged(boxes[CHILD_LAB].kid))
1870 	    {
1871 		delta += boxes[CHILD_LAB].box.width +
1872 		    (MGR_ShadowThickness(scale) << 1);
1873 		if (delta > 0)
1874 		    delta = 0;
1875 	    }
1876 	    for (i = 0; boxes[i].kid; i++)
1877 	    {
1878 		boxes[i].box.x += delta;
1879 	    }
1880 	}
1881 
1882 	/* T. Straumann: adjust height / tickmark positions if our geometry
1883 	 * is different from the one used in _XmScalePreferredSize()
1884 	 *
1885 	 * They do this only if Scale_ScaleWidth() == 0 or delta < 0
1886 	 * as can be confirmed by test14. Try also to resize
1887 	 *
1888 	 *   test13 -xrm "*scaleHeight:200"
1889 	 *
1890 	 * using the WM
1891 	 */
1892 	delta = XtHeight(scale) - curh;
1893 	if ( delta < 0 || (delta > 0 && 0 == Scale_ScaleHeight(scale) ) )
1894 	{
1895 		/* different layout whether one or more tick marks are present */
1896 		int denom = (num_children == 3 ? 2 : num_children -3);
1897 		for (i = 0; boxes[i].kid; i++)
1898 		{
1899 			switch (i)
1900 			{
1901 				/* adjust the height of SB and LAB */
1902 				case CHILD_LAB:
1903 				case CHILD_SB:
1904 					boxes[i].box.height = XtHeight(scale);
1905 				break;
1906 
1907 				/* adjust the tick marks */
1908 				default:
1909 					boxes[i].box.y += delta * (i - 2) / denom;
1910 				break;
1911 			}
1912 		}
1913 	}
1914     }
1915 }
1916 
1917 
1918 /*
1919  * if we've gotten here, layout the children
1920  */
1921 static void
_XmScaleConfigureChildren(Widget scale,Widget child,XmKidGeometry boxes)1922 _XmScaleConfigureChildren(Widget scale, Widget child, XmKidGeometry boxes)
1923 {
1924     int inc;
1925     int p_inc;
1926 
1927     _XmSetKidGeo(boxes, child);
1928 
1929     Scale_SliderSize(scale) = _XmScaleConvertWidthToSliderSize(scale);
1930     _XmScaleConvertScaleIncrementToSCBIncrements(scale, &inc, &p_inc);
1931 
1932     XmScrollBarSetValues(boxes[CHILD_SB].kid,
1933 			 _XmScaleConvertScaleValueToSCBValue(scale),
1934 			 Scale_SliderSize(scale),
1935 			 inc, p_inc, False);
1936 }
1937 
1938 
1939 static void
computeValueSize(Widget w)1940 computeValueSize(Widget w)
1941 {
1942     int maxlen, maxval;
1943 
1944 #if 0
1945     maxval = ( Scale_Maximum(w) > -Scale_Minimum(w) ) ?
1946                 Scale_Maximum(w) :
1947                 Scale_Minimum(w);
1948 
1949     maxlen = ( maxval < 0 ) ? 2 : 1;
1950 #else
1951     maxval = abs(Scale_Maximum(w)) > abs(Scale_Minimum(w)) ? abs(Scale_Maximum(w)) : abs(Scale_Minimum(w));
1952     if (Scale_Maximum(w) < 0 || Scale_Minimum(w) < 0)
1953     {
1954     	maxlen = 2;
1955     }
1956     else
1957     {
1958     	maxlen = 1;
1959     }
1960 #endif
1961 
1962     for (maxval = abs(maxval); maxval >= 10; maxlen++)
1963     {
1964         maxval /= 10;
1965     }
1966 
1967     if (Scale_DecimalPoints(w))
1968     {
1969         maxlen++;
1970         maxlen = maxlen < 3 ? 3 : maxlen;
1971     }
1972 
1973     Scale_ShowValueWidth(w) = 2 + Scale_FontStruct(w)->max_bounds.width * maxlen;
1974     Scale_ShowValueHeight(w) = 3 + Scale_FontStruct(w)->max_bounds.ascent +
1975         Scale_FontStruct(w)->max_bounds.descent;
1976 }
1977 
1978 
1979 static void
showValue(Widget w,int scb_value,int scale_value)1980 showValue(Widget w, int scb_value, int scale_value)
1981 {
1982     char buf[256];
1983     Widget sb;
1984 
1985     sb = ((XmScaleWidget)w)->composite.children[CHILD_SB];
1986     valueToString(w, buf);
1987 
1988 #if 1
1989 /* Fix from John Richardson <jrichard@zko.dec.com> 1/7/1996 */
1990 	/* T. Straumann: only erase if Scale_ShowValueX() is valid */
1991     if (XtIsRealized(w) && SHOW_VALUE_X_INVALID != Scale_ShowValueX(w))
1992     {
1993 	XFillRectangle(XtDisplay(w), XtWindow(w), MGR_BackgroundGC(w),
1994 		       Scale_ShowValueX(w), Scale_ShowValueY(w),
1995 		       Scale_ShowValueWidth(w), Scale_ShowValueHeight(w));
1996     }
1997 #else
1998     if (XtIsRealized(w))
1999     {
2000 	XFillRectangle(XtDisplay(w), XtWindow(w), MGR_BackgroundGC(w),
2001 		Scale_ShowValueX(w), Scale_ShowValueY(w) - Scale_FontStruct(w)->descent,
2002 		Scale_ShowValueWidth(w), Scale_ShowValueHeight(w));
2003     }
2004 #endif
2005 
2006     if (Scale_Orientation(w) == XmHORIZONTAL)
2007     {
2008 	Scale_ShowValueX(w) = SCB_SliderX(sb) + (SCB_SliderWidth(sb) >> 1) -
2009 	    (Scale_ShowValueWidth(w) / 2) + XtX(sb);
2010 
2011 	Scale_ShowValueY(w) = XtY(sb) - Scale_ShowValueHeight(w);
2012     }
2013     else if (Scale_Orientation(w) == XmVERTICAL)
2014     {
2015 	Scale_ShowValueY(w) = SCB_SliderY(sb) + (SCB_SliderHeight(sb) >> 1) -
2016 	    (Scale_ShowValueHeight(w) / 2) + XtY(sb);
2017 
2018 	Scale_ShowValueX(w) = XtX(sb) - Scale_ShowValueWidth(w);
2019     }
2020     else
2021     {
2022 	_XmError(w, "Scale Orientation wrong.");
2023     }
2024 
2025     if (XtIsRealized(w))
2026     {
2027 	int offset;
2028 
2029 	offset = (Scale_ShowValueWidth(w) -
2030 		  XTextWidth(Scale_FontStruct(w), buf, strlen(buf))) ;
2031 	if (Scale_Orientation(w) == XmHORIZONTAL)
2032 	{
2033 	    XDrawString(XtDisplay(w), XtWindow(w),
2034 			Scale_ForegroundGC(w),
2035 			Scale_ShowValueX(w) + offset / 2,
2036 			Scale_ShowValueY(w) + Scale_FontStruct(w)->ascent,
2037 			buf, strlen(buf));
2038 	}
2039 	else if (Scale_Orientation(w) == XmVERTICAL)
2040 	{
2041 	    XDrawString(XtDisplay(w), XtWindow(w),
2042 			Scale_ForegroundGC(w),
2043 			Scale_ShowValueX(w) + offset,
2044 			Scale_ShowValueY(w) + Scale_FontStruct(w)->ascent,
2045 			buf, strlen(buf));
2046 	}
2047 	else
2048 	    _XmError(w, "Scale Orientation wrong");
2049     }
2050 }
2051 
2052 
2053 static void
_ScaleValueChanged(Widget sb,XtPointer cd,XtPointer data)2054 _ScaleValueChanged(Widget sb, XtPointer cd, XtPointer data)
2055 {
2056     XmScrollBarCallbackStruct *cbs = (XmScrollBarCallbackStruct *)data;
2057     XmScaleCallbackStruct scbs;
2058     int scale_value;
2059 
2060     Scale_LastValue(XtParent(sb)) = Scale_Value(sb);
2061     scale_value = _XmScaleConvertSCBValueToScaleValue(XtParent(sb), cbs->value);
2062     Scale_Value(XtParent(sb)) = scale_value;
2063 
2064     if (Scale_ShowValue(XtParent(sb)))
2065     {
2066 	showValue(XtParent(sb), cbs->value, scale_value);
2067     }
2068 
2069     scbs.reason = cbs->reason;
2070     scbs.event = cbs->event;
2071     scbs.value = scale_value;
2072 
2073     if (Scale_ValueChangedCallback(XtParent(sb)))
2074     {
2075 	XtCallCallbackList(XtParent(sb),
2076 			   Scale_ValueChangedCallback(XtParent(sb)), &scbs);
2077     }
2078 }
2079 
2080 
2081 static void
_ScaleDrag(Widget sb,XtPointer cd,XtPointer data)2082 _ScaleDrag(Widget sb, XtPointer cd, XtPointer data)
2083 {
2084     XmScrollBarCallbackStruct *cbs = (XmScrollBarCallbackStruct *)data;
2085     XmScaleCallbackStruct scbs;
2086     int scale_value;
2087 
2088 #if XmVERSION > 1
2089     if (! Scale_Editable(XtParent(sb)))
2090 	return;
2091 #endif
2092 
2093     Scale_LastValue(XtParent(sb)) = Scale_Value(sb);
2094     scale_value = _XmScaleConvertSCBValueToScaleValue(XtParent(sb), cbs->value);
2095     Scale_Value(XtParent(sb)) = scale_value;
2096 
2097     if (Scale_ShowValue(XtParent(sb)))
2098     {
2099 	showValue(XtParent(sb), cbs->value, scale_value);
2100     }
2101 
2102     scbs.reason = cbs->reason;
2103     scbs.event = cbs->event;
2104     scbs.value = scale_value;
2105     if (Scale_DragCallback(XtParent(sb)))
2106     {
2107 	XtCallCallbackList(XtParent(sb),
2108 			   Scale_DragCallback(XtParent(sb)), &scbs);
2109     }
2110 }
2111 
2112 
2113 #if 0
2114 static void
2115 GetFocus(Widget w, XEvent *event, String *params, Cardinal *num_params)
2116 {
2117     XmScrollBarWidget sb;
2118 
2119     DEBUGOUT(_LtDebug(__FILE__, w, "GetFocus\n"));
2120 
2121     sb = (XmScrollBarWidget)(((XmScaleWidget)w)->composite.children[CHILD_SB]);
2122 
2123     XtCallActionProc((Widget)sb, "PrimitiveFocusIn", event,
2124 		     params, *num_params);
2125 }
2126 
2127 
2128 static void
2129 LoseFocus(Widget w, XEvent *event, String *params, Cardinal *num_params)
2130 {
2131     XmScrollBarWidget sb;
2132 
2133     DEBUGOUT(_LtDebug(__FILE__, w, "LoseFocus\n"));
2134 
2135     sb = (XmScrollBarWidget)(((XmScaleWidget)w)->composite.children[CHILD_SB]);
2136 
2137     XtCallActionProc((Widget)sb, "PrimitiveFocusOut", event,
2138 		     params, *num_params);
2139 }
2140 #endif /* 0 */
2141 
2142 
2143 static int
_XmScaleConvertWidthToSliderSize(Widget w)2144 _XmScaleConvertWidthToSliderSize(Widget w)
2145 {
2146     int ret, last_ret;
2147     XmScrollBarWidget sb;
2148     Dimension ht;
2149     Dimension st;
2150 
2151     /* FIX ME: the next two statements are a kludge */
2152     sb = (XmScrollBarWidget)(((XmScaleWidget)w)->composite.children[CHILD_SB]);
2153 
2154     /* FIX ME: Can't we use scale's values here? I.o.w. what shouls scale do
2155      * when these values are set explicitly and thus differ from scale's ?
2156      */
2157     XtVaGetValues((Widget)sb,
2158 		  XmNhighlightThickness, &ht,
2159 		  XmNshadowThickness, &st,
2160 		  NULL);
2161 
2162     ret = Scale_SliderSize(w);
2163     do
2164     {
2165 	/* FIX ME: rework the if's */
2166 	last_ret = ret;
2167 	if (Scale_Orientation(w) == XmHORIZONTAL)
2168 	{
2169 	    if (XtWidth(sb) == 2 * (ht + st))
2170 	    {
2171 		/* Note: M*tif 1.2.2 SIGFPE's on this -- PvH */
2172 		ret = (int)((double)(SCB_MAX - SCB_MIN) /
2173 			    (double)(Scale_Maximum(w) - Scale_Minimum(w)) *
2174 			    (double)HSLIDERSIZE);
2175 	    }
2176 	    else if (XtWidth(sb) < HSLIDERSIZE)
2177 	    {
2178 		ret = SCB_MAX - SCB_MIN;
2179 	    }
2180 	    else
2181 	    {
2182 		/* Note: M*tif doesn't use float arithmetic here -- PvH */
2183 		ret = (int)((SCB_MAX - SCB_MIN) /
2184 			    (XtWidth(sb) - 2 * (ht + st)) *
2185 			    HSLIDERSIZE);
2186 	    }
2187 	}
2188 	else
2189 	{
2190 	    if (XtHeight(sb) == 2 * (ht + st))
2191 	    {
2192 		ret = (int)((float)(SCB_MAX - SCB_MIN) /
2193 			    (float)(Scale_Maximum(w) - Scale_Minimum(w)) *
2194 			    (float)HSLIDERSIZE);
2195 	    }
2196 	    else if (XtHeight(sb) < HSLIDERSIZE)
2197 	    {
2198 		ret = SCB_MAX - SCB_MIN;
2199 	    }
2200 	    else
2201 	    {
2202 		/* Note: M*tif doesn't use float arithmetic here -- PvH */
2203 		ret = (int)((SCB_MAX - SCB_MIN) /
2204 			    (XtHeight(sb) - 2 * (ht + st)) *
2205 			    HSLIDERSIZE);
2206 	    }
2207 	}
2208     }
2209     while (last_ret != ret);
2210 
2211     return ret;
2212 }
2213 
2214 
2215 static int
_XmScaleConvertSCBValueToScaleValue(Widget w,int value)2216 _XmScaleConvertSCBValueToScaleValue(Widget w, int value)
2217 {
2218     double roundarg;
2219     int result;
2220 
2221     DEBUGOUT(_LtDebug(__FILE__, w, "_XmScaleConvertSCBValueToScaleValue(,%i)\n",
2222                        value));
2223     if ((SCB_MAX - SCB_MIN - Scale_SliderSize(w)) == 0)
2224     {
2225 	return Scale_Minimum(w);
2226     }
2227 
2228     roundarg = (double)(Scale_Maximum(w) - Scale_Minimum(w))
2229 	     * (double)value
2230 	     / (double)(SCB_MAX - SCB_MIN - Scale_SliderSize(w))
2231 	     + (double)Scale_Minimum(w);
2232 
2233     result = (int)(roundarg + 0.5);
2234 
2235     return result;
2236 }
2237 
2238 
2239 static int
_XmScaleConvertScaleValueToSCBValue(Widget w)2240 _XmScaleConvertScaleValueToSCBValue(Widget w)
2241 {
2242 
2243     double roundarg;
2244     int result;
2245 
2246     DEBUGOUT(_LtDebug(__FILE__, w, "_XmScaleConvertScaleValueToSCBValue()\n"));
2247     roundarg = (double)(Scale_Value(w) - Scale_Minimum(w))
2248 	     * (double)(SCB_MAX - SCB_MIN - Scale_SliderSize(w))
2249 	     / (double)(Scale_Maximum(w) - Scale_Minimum(w));
2250     /* amai: is this the correct formula?
2251              looks like the old one in _XmScaleConvertSCBValueToScaleValue() */
2252     result = (int)(roundarg);
2253     return result;
2254 }
2255 
2256 
2257 static void
_XmScaleConvertScaleIncrementToSCBIncrements(Widget w,int * inc,int * page_inc)2258 _XmScaleConvertScaleIncrementToSCBIncrements(Widget w,
2259 					 int* inc,
2260 					 int* page_inc)
2261 {
2262     *inc = (int)((double)(SCB_MAX - SCB_MIN - Scale_SliderSize(w)) /
2263 		 (double)(Scale_Maximum(w) - Scale_Minimum(w)) +
2264 		 0.5);
2265     *inc = _XmMax(*inc, 1);	/* FIX ME */
2266     *page_inc = *inc * Scale_ScaleMultiple(w);
2267 }
2268 
2269 
2270 static void
_XmScaleProcessingDirectionDefault(Widget w,int offset,XrmValue * val)2271 _XmScaleProcessingDirectionDefault(Widget w, int offset, XrmValue *val)
2272 {
2273     static unsigned char direction;
2274     XmScaleWidget sw = (XmScaleWidget)w;
2275 
2276     if (sw->scale.orientation == XmVERTICAL)
2277     {
2278 	direction = XmMAX_ON_TOP;
2279     }
2280     else
2281     {
2282 	direction = XmMAX_ON_RIGHT;	/* FIX ME */
2283     }
2284 
2285     val->addr = (XPointer)&direction;
2286 }
2287