1 /*----------------------------------------------------------------------------
2 --
3 --  Module:           XmUbArrowLabel
4 --
5 --  Project:          XmUb - Ulle's Motif widgets
6 --  System:
7 --    Subsystem:      <>
8 --    Function block: <>
9 --
10 --  Description:
11 --    This is the implementation of the widget.
12 --
13 --  Filename:         XmUbArrLab.c
14 --
15 --  Authors:          Roger Larsson, Ulrika Bornetun
16 --  Creation date:    1992-04-28
17 --
18 --
19 --  (C) Copyright Ulrika Bornetun, Roger Larsson (1995)
20 --      All rights reserved
21 --
22 --  Permission to use, copy, modify, and distribute this software and its
23 --  documentation for any purpose and without fee is hereby granted,
24 --  provided that the above copyright notice appear in all copies. Ulrika
25 --  Bornetun and Roger Larsson make no representations about the usability
26 --  of this software for any purpose. It is provided "as is" without express
27 --  or implied warranty.
28 ----------------------------------------------------------------------------*/
29 
30 /* SCCS module identifier. */
31 static char SCCSID[] = "@(#) Module: XmUbArrLab.c, Version: 1.1, Date: 95/02/18 15:10:06";
32 
33 
34 /*----------------------------------------------------------------------------
35 --  Include files
36 ----------------------------------------------------------------------------*/
37 
38 #include <stdio.h>
39 #include <string.h>
40 #include <X11/Intrinsic.h>
41 #include <X11/StringDefs.h>
42 #include <Xm/XmP.h>
43 
44 #include <Xm/Label.h>
45 #include <Xm/ArrowB.h>
46 
47 /* Private widget header file. */
48 #include "XmUbArrLabP.h"
49 
50 /*----------------------------------------------------------------------------
51 --  Macro definitions
52 ----------------------------------------------------------------------------*/
53 
54 #ifdef MAX
55 #undef MAX
56 #endif
57 
58 #ifdef MIN
59 #undef MIN
60 #endif
61 
62 #define MAX( x, y )  ( ( x ) > ( y ) ? ( x ) : ( y ) )
63 #define MIN( x, y )  ( ( x ) < ( y ) ? ( x ) : ( y ) )
64 
65 #define XmUbAL_CHILD_ERROR  -1
66 
67 /* Resource converters. */
68 #define XmRarrowPlacement  "ArrowPlacement"
69 
70 
71 /*----------------------------------------------------------------------------
72 --  Type declarations
73 ----------------------------------------------------------------------------*/
74 
75 typedef struct {
76 
77   Dimension  width;
78   Dimension  height;
79   Position   x;
80   Position   y;
81 
82 } KidDimensionRec;
83 
84 /*----------------------------------------------------------------------------
85 --  Global definitions
86 ----------------------------------------------------------------------------*/
87 
88 /* Internal Motif functions (how do we know about this....?) */
89 extern void
90   _XmBackgroundColorDefault();
91 
92 
93 /* The arrow label resource list. */
94 static XtResource resources[] = {
95   {
96     XmNactivateCallback,
97     XmCCallback,
98     XmRCallback, sizeof( XtCallbackList ),
99     XtOffset( XmUbArrowLabelWidget, al.activate_callback ),
100     XmRCallback,
101     NULL
102   },
103   {
104     XmNlabelString,
105     XmCXmString,
106     XmRXmString, sizeof( XmString ),
107     XtOffset( XmUbArrowLabelWidget, al.label_string ),
108     XtRImmediate,
109     (XtPointer) NULL
110   },
111   {
112     XmNmarginHeight,
113     XmCMarginHeight,
114     XtRDimension, sizeof( Dimension ),
115     XtOffset( XmUbArrowLabelWidget, al.margin_height ),
116     XtRImmediate,
117     (XtPointer) 0
118   },
119   {
120     XmNmarginWidth,
121     XmCMarginWidth,
122     XtRDimension, sizeof( Dimension ),
123     XtOffset( XmUbArrowLabelWidget, al.margin_width ),
124     XtRImmediate,
125     (XtPointer) 0
126   },
127   {
128     XmUbNalArrowOrientation,
129     XmCOrientation,
130     XmROrientation, sizeof( unsigned char ),
131     XtOffset( XmUbArrowLabelWidget, al.arrow_orientation ),
132     XmRImmediate,
133     (XtPointer) XmHORIZONTAL
134   },
135   {
136     XmUbNalArrowPlacement,
137     XmUbCAlArrowPlacement,
138     XmRarrowPlacement, sizeof( arrowPlacement ),
139     XtOffset( XmUbArrowLabelWidget, al.arrow_placement ),
140     XmRImmediate,
141     (XtPointer) XmUbARROWS_SPREAD_OUT
142   },
143   {
144     XmNspacing,
145     XmCSpacing,
146     XtRDimension, sizeof( Dimension ),
147     XtOffset( XmUbArrowLabelWidget, al.spacing ),
148     XtRImmediate,
149     (XtPointer) 2
150   },
151   {
152     XmUbNalRecomputeHeight,
153     XmUbCAlRecomputeHeight,
154     XtRBoolean, sizeof( Boolean ),
155     XtOffset( XmUbArrowLabelWidget, al.recompute_height ),
156     XtRImmediate,
157     (XtPointer) True
158   },
159   {
160     XmUbNalRecomputeWidth,
161     XmUbCAlRecomputeWidth,
162     XtRBoolean, sizeof( Boolean ),
163     XtOffset( XmUbArrowLabelWidget, al.recompute_width ),
164     XtRImmediate,
165     (XtPointer) True
166   },
167 
168 };  /* resources */
169 
170 
171 /*----------------------------------------------------------------------------
172 --  Function prototypes
173 ----------------------------------------------------------------------------*/
174 
175 /* Class methods. */
176 static void
177   ClassInitialize();
178 
179 static void
180   ChangeManaged( Widget  widget );
181 
182 static void
183   DeleteChild( Widget  widget );
184 
185 static void
186   Destroy( Widget   widget );
187 
188 static XtGeometryResult
189   GeometryManager( Widget            widget,
190                    XtWidgetGeometry  *request,
191                    XtWidgetGeometry  *reply );
192 
193 static void
194   Initialize( Widget     treq,
195               Widget     tnew,
196               ArgList    args,
197               Cardinal   *num_args );
198 
199 static void
200   InsertChild( Widget  widget );
201 
202 static XtGeometryResult
203   QueryGeometry( Widget             widget,
204                  XtWidgetGeometry  *proposed,
205                  XtWidgetGeometry  *answer );
206 
207 static void
208   Resize( Widget    widget );
209 
210 static Boolean
211   SetValues( Widget     current,
212              Widget     request,
213              Widget     new,
214              ArgList    args,
215              Cardinal   *num_args );
216 
217 
218 /* Internal functions. */
219 
220 
221 static void
222   ArrowButtonActivatedCB( Widget                       arrow_button,
223                           XmUbArrowLabelWidget         al,
224                           XmArrowButtonCallbackStruct  *call_data );
225 
226 /* If not in the child list, returns XmUbMD_CHILD_ERROR. */
227 static int
228   ChildIndex( XmUbArrowLabelWidget  al,
229               Widget                child );
230 
231 static void
232   ConvertToArrowPlacement( XrmValue   *args,
233                            Cardinal   *num_args,
234                            XrmValue   *from,
235                            XrmValue   *to );
236 
237 
238 static void
239   CreateInternalWidgets( XmUbArrowLabelWidget  al );
240 
241 /* The sizes array  must have been processed by GetChildPrefSizes
242    before DoLayout is called. */
243 static void
244   DoLayout( XmUbArrowLabelWidget  al,
245             KidDimensionRec       sizes[] );
246 
247 /* Fills in the width and height fields in the kids dimension recs. */
248 static void
249   GetChildPrefSizes( XmUbArrowLabelWidget  al,
250                      Widget                initiator,
251                      XtWidgetGeometry      *request,
252                      KidDimensionRec       sizes[] );
253 
254 
255 /* The sizes array must have been prepared by GetChildPrefSizes before this
256    function is called. */
257 static void
258   GetOwnPreferredSize( XmUbArrowLabelWidget  al,
259                        KidDimensionRec       sizes[],
260                        Dimension             *pref_width,
261                        Dimension             *pref_height );
262 
263 static void
264   GetValuesHook( Widget    w,
265                  ArgList   args,
266                  Cardinal  *num_args );
267 
268 static void
269   KidsPreferredGeometry( Widget            kid,
270                          Widget            initiator,
271                          XtWidgetGeometry  *request,
272                          XtWidgetGeometry  *desired );
273 
274 /* ResizeIfNeeded fills in the sizes array. Does not have to be initialized. */
275 static Boolean
276   ResizeIfNeeded( XmUbArrowLabelWidget  al,
277                   KidDimensionRec       sizes[] );
278 
279 static void
280   WarningNoResourceChange( XmUbArrowLabelWidget  al,
281                            String                resource );
282 
283 /*----------------------------------------------------------------------------
284 --  Initialization of the class record.
285 ----------------------------------------------------------------------------*/
286 
287 /* This initialization has to be done after the methods have been declared. */
288 XmUbArrowLabelClassRec xmUbArrowLabelClassRec = {
289 
290   { /* Core class fields. */
291     /* superclass */                    (WidgetClass) &xmManagerClassRec,
292     /* class_name */                    "XmUbArrowLabel",
293     /* widget_size */                   sizeof( XmUbArrowLabelRec ),
294     /* class_initialize */              ClassInitialize,
295     /* class_part_initialize */         NULL,
296     /* class_inited */                  False,
297     /* initialize */                    Initialize,
298     /* initialize_hook */               NULL,
299     /* realize */                       XtInheritRealize,
300     /* actions */                       NULL,
301     /* num_actions */                   0,
302     /* resources */                     resources,
303     /* num_resources */                 XtNumber( resources ),
304     /* xrm_class */                     NULLQUARK,
305     /* compress_motion */               True,
306     /* compress_exposure */             True,
307     /* compress_enterleave */           True,
308     /* visible_interest */              False,
309     /* destroy */                       Destroy,
310     /* resize */                        Resize,
311     /* expose */                        NULL,
312     /* set_values */                    SetValues,
313     /* set_values_hook */               NULL,
314     /* set_values_almost */             XtInheritSetValuesAlmost,
315     /* get_values_hook */               GetValuesHook,
316     /* accept_focus */                  NULL,
317     /* version */                       XtVersion,
318     /* callback_private */              NULL,
319     /* tm_table */                      NULL,
320     /* query_geometry */                QueryGeometry,
321     /* display_accelerator */           XtInheritDisplayAccelerator,
322     /* extension */                     NULL
323   },
324   { /* Composite class part. */
325     /* geometry_manager */              GeometryManager,
326     /* change_managed */                ChangeManaged,
327     /* insert_child */                  InsertChild,
328     /* delete_child */                  DeleteChild,
329     /* extension */                     NULL
330   },
331   { /* Constraint class fields. */
332     /* subresources */                  NULL,
333     /* subresource_count */             0,
334     /* constraint_size */               sizeof(
335                                           XmUbArrowLabelConstraintsRec ),
336     /* initialize */                    NULL,
337     /* destroy */                       NULL,
338     /* set_values */                    NULL,
339     /* extension */                     NULL
340   },
341   { /* XmManager class part. */
342     /* translations */                  NULL,
343     /* get_resources */                 NULL,
344     /* num_get_resources */             0,
345     /* get_constraint_resources */      NULL,
346     /* num_get_constraint_resources */  0,
347     /* extension */                     NULL
348   },
349   { /* Arrow label class part. */
350     /* extension */                     NULL
351   },
352 
353 };
354 
355 
356 /* Class record pointer. */
357 WidgetClass
358   xmUbArrowLabelWidgetClass = (WidgetClass) &xmUbArrowLabelClassRec;
359 
360 
361 
362 /*----------------------------------------------------------------------------
363 --  Functions
364 ----------------------------------------------------------------------------*/
365 
366 
367 static void
ArrowButtonActivatedCB(Widget arrow_button,XmUbArrowLabelWidget al,XmArrowButtonCallbackStruct * call_data)368   ArrowButtonActivatedCB( Widget                       arrow_button,
369                           XmUbArrowLabelWidget         al,
370                           XmArrowButtonCallbackStruct  *call_data )
371 {
372   /* Variables. */
373   XmUbArrowLabelCallbackStruct  cb;
374   int                           child_index;
375 
376   /* Code. */
377 
378   /* Find out if it was the forwards or backwards button that was pressed. */
379   child_index = ChildIndex( al, arrow_button );
380 
381   switch( child_index ){
382 
383     case XmUbAL_CHILD_BACK_ARROW:
384       cb.reason = XmUbCR_BACK_ARROW_ACTIVATED;
385       break;
386 
387     case XmUbAL_CHILD_FORWARD_ARROW:
388       cb.reason = XmUbCR_FORWARD_ARROW_ACTIVATED;
389       break;
390 
391     default:
392       /* Something is wrong. */
393       return;
394   }
395 
396   cb.event = call_data -> event;
397   cb.child = arrow_button;
398 
399   /* Invoke the callbacks. */
400   XtCallCallbackList( (Widget) al, al -> al.activate_callback,
401                       (XtPointer) &cb );
402 
403 
404   return;
405 
406 } /* ArrowButtonActivatedCB */
407 
408 
409 /*----------------------------------------------------------------------*/
410 
411 static void
ClassInitialize()412   ClassInitialize()
413 {
414   /* Code. */
415 
416   /* Register type converters. */
417   XtAddConverter( XmRString, XmRarrowPlacement,
418                   ConvertToArrowPlacement, NULL, 0 );
419 
420   return;
421 
422 } /* ClassInitialize */
423 
424 
425 /*----------------------------------------------------------------------*/
426 
427 static void
ChangeManaged(Widget widget)428   ChangeManaged( Widget  widget )
429 {
430   /* Variables. */
431   Boolean               layout_done;
432   KidDimensionRec       kids_sizes[ NO_INTERNAL_CHILDREN ];
433   XmUbArrowLabelWidget  al;
434 
435 
436   /* Code. */
437 
438   al = (XmUbArrowLabelWidget) widget;
439 
440   /* ResizeIfNeeded checks the size of all children and resizes the widget. */
441   layout_done = ResizeIfNeeded( al, kids_sizes );
442 
443   /* Do the layout. */
444   if( !layout_done )
445     DoLayout( al, kids_sizes );
446 
447 
448   return;
449 
450 } /* ChangeManaged */
451 
452 
453 /*----------------------------------------------------------------------*/
454 
455 static int
ChildIndex(XmUbArrowLabelWidget al,Widget child)456   ChildIndex( XmUbArrowLabelWidget  al,
457               Widget                child )
458 {
459   /* Variables. */
460   int  index;
461 
462   /* Code. */
463 
464   for( index = 0; index < NO_INTERNAL_CHILDREN; index ++ ){
465 
466     if( al -> al.internal_children[ index ] == child )
467       return index;
468 
469   } /* for */
470 
471 
472   /* Specified child not found. */
473   return XmUbAL_CHILD_ERROR;
474 
475 } /* ChildIndex */
476 
477 
478 /*----------------------------------------------------------------------*/
479 
480 static void
ConvertToArrowPlacement(XrmValue * args,Cardinal * num_args,XrmValue * from,XrmValue * to)481   ConvertToArrowPlacement( XrmValue   *args,
482                            Cardinal   *num_args,
483                            XrmValue   *from,
484                            XrmValue   *to )
485 {
486 
487   /* Variables. */
488   static arrowPlacement  conv_arrow_placement;
489 
490 
491   /* Code. */
492 
493   if( *num_args != 0 )
494     XtWarningMsg( "wrongParameters", "ConvertToArrowPlacement",
495       "XtToolkitError", "Conversion needs no extra arguments",
496       (String *) NULL, (Cardinal *) NULL );
497 
498   if( strcmp( (char *) from -> addr, "ARROWS_LEFT" ) == 0 )
499     conv_arrow_placement = XmUbARROWS_LEFT;
500 
501   else if( strcmp( (char *) from -> addr, "ARROWS_SPREAD_OUT" ) == 0 )
502     conv_arrow_placement = XmUbARROWS_SPREAD_OUT;
503 
504   else if( strcmp( (char *) from -> addr, "ARROWS_RIGHT" ) == 0 )
505     conv_arrow_placement = XmUbARROWS_RIGHT;
506 
507   else {
508     XtWarningMsg( "wrongParameters", "ConvertToArrowPlacement",
509       "XtToolkitError", "Cannot convert to type arrowPlacement",
510       (String *) NULL, (Cardinal *) 0 );
511     conv_arrow_placement = XmUbARROWS_SPREAD_OUT;
512   }
513 
514   ( *to ).size = sizeof( arrowPlacement );
515   ( *to ).addr = (XtPointer) &conv_arrow_placement;
516 
517 
518   return;
519 
520 } /* ConvertToArrowPlacement */
521 
522 
523 /*----------------------------------------------------------------------*/
524 
525 static void
CreateInternalWidgets(XmUbArrowLabelWidget al)526   CreateInternalWidgets( XmUbArrowLabelWidget  al )
527 {
528   /* Variables. */
529   Arg           args[ 5 ];
530   Cardinal      n;
531   char          *name_buffer;
532   String        wname;
533 
534   /* Code. */
535 
536   /* Get the name of the "parent" widget. */
537   wname = XtName( (Widget)al );
538 
539   name_buffer = XtMalloc( strlen( wname ) + 4 );
540 
541   /* The two arrow buttons. */
542   /* Backwards button. */
543   sprintf( name_buffer, "%sBa", wname );
544   n = 0;
545   if( al -> al.arrow_orientation == XmHORIZONTAL ){
546     XtSetArg( args[ n ], XmNarrowDirection, XmARROW_LEFT ); n++;
547   } else {
548     XtSetArg( args[ n ], XmNarrowDirection, XmARROW_UP ); n++;
549   }
550 
551   al -> al.internal_children[ XmUbAL_CHILD_BACK_ARROW ] =
552     XmCreateArrowButton( (Widget) al, name_buffer, args, n );
553 
554   XtAddCallback( al -> al.internal_children[ XmUbAL_CHILD_BACK_ARROW ],
555                  XmNactivateCallback,
556                  (XtCallbackProc) ArrowButtonActivatedCB, (XtPointer) al );
557 
558   /* Forward button. */
559   sprintf( name_buffer, "%sFa", wname );
560   n = 0;
561   if( al -> al.arrow_orientation == XmHORIZONTAL ){
562     XtSetArg( args[ n ], XmNarrowDirection, XmARROW_RIGHT ); n++;
563   } else {
564     XtSetArg( args[ n ], XmNarrowDirection, XmARROW_DOWN ); n++;
565   }
566 
567   al -> al.internal_children[ XmUbAL_CHILD_FORWARD_ARROW ] =
568     XmCreateArrowButton( (Widget) al, name_buffer, args, n );
569 
570   XtAddCallback( al -> al.internal_children[ XmUbAL_CHILD_FORWARD_ARROW ],
571                  XmNactivateCallback,
572                  (XtCallbackProc) ArrowButtonActivatedCB, (XtPointer) al );
573 
574   /* The label. */
575   sprintf( name_buffer, "%sLb", wname );
576 
577   n = 0;
578   if( al -> al.label_string != NULL ){
579     XtSetArg( args[ n ], XmNlabelString, al -> al.label_string ); n++;
580   }
581 
582   al -> al.internal_children[ XmUbAL_CHILD_LABEL ] =
583     XmCreateLabel( (Widget) al, name_buffer, args, n );
584 
585 
586   XtManageChildren( al -> al.internal_children, NO_INTERNAL_CHILDREN );
587 
588   XtFree( name_buffer );
589 
590 
591   return;
592 
593 } /* CreateInternalWidgets */
594 
595 
596 /*----------------------------------------------------------------------*/
597 
598 static void
DeleteChild(Widget widget)599   DeleteChild( Widget  widget )
600 {
601 
602   /* Variables. */
603   int                   index;
604   XmUbArrowLabelWidget  al;
605 
606   /* Code. */
607 
608   al = (XmUbArrowLabelWidget) XtParent( widget );
609 
610   /* Clear the internal reference. */
611   for( index = 0; index < NO_INTERNAL_CHILDREN; index ++ ){
612     if( al -> al.internal_children[ index ] == widget ){
613       al -> al.internal_children[ index ] = NULL;
614       break;
615     }
616   }
617 
618   /* Perform the actual operation */
619   (* ( (CompositeWidgetClass) (xmUbArrowLabelWidgetClass ->
620      core_class.superclass) ) -> composite_class.delete_child ) ( widget );
621 
622 
623   return;
624 
625 } /* DeleteChild */
626 
627 
628 /*----------------------------------------------------------------------*/
629 
630 static void
Destroy(Widget widget)631   Destroy( Widget   widget )
632 {
633   /* Variables. */
634   XmUbArrowLabelWidget  al;
635 
636   /* Code. */
637 
638   al = (XmUbArrowLabelWidget) widget;
639 
640   /* Free copied XmStrings. */
641   if( al -> al.label_string != NULL )
642     XmStringFree( al -> al.label_string );
643 
644   /* Remove callbacks. */
645   XtRemoveAllCallbacks( widget, XmNactivateCallback );
646 
647 
648   return;
649 
650 } /* Destroy */
651 
652 
653 /*----------------------------------------------------------------------*/
654 
655 static void
DoLayout(XmUbArrowLabelWidget al,KidDimensionRec sizes[])656   DoLayout( XmUbArrowLabelWidget  al,
657             KidDimensionRec       sizes[] )
658 {
659   /* Variables. */
660   int        index;
661   Widget     kid;
662   Dimension  max_height;
663   Dimension  offset;
664 
665   /* Code. */
666 
667   /* Let the arrows keep their sizes, and let the label size shrink and
668      grow. */
669 
670   /* Start by calculating the label's width. */
671   offset = sizes[ XmUbAL_CHILD_BACK_ARROW ].width +
672            sizes[ XmUbAL_CHILD_FORWARD_ARROW ].width +
673            2 * al -> al.margin_width + 2 * al -> al.spacing;
674 
675   if( offset > al -> core.width )
676     sizes[ XmUbAL_CHILD_LABEL ].width = 1;
677   else
678     sizes[ XmUbAL_CHILD_LABEL ].width = al -> core.width - offset;
679 
680   /* The widgets may keep their heights. */
681 
682   /* The placement resource decides the x position. */
683   switch( al -> al.arrow_placement ){
684 
685     case XmUbARROWS_LEFT:
686       sizes[ XmUbAL_CHILD_BACK_ARROW ].x = (Position) al -> al.margin_width;
687 
688       sizes[ XmUbAL_CHILD_FORWARD_ARROW ].x =
689         sizes[ XmUbAL_CHILD_BACK_ARROW ].x +
690         (Position) sizes[ XmUbAL_CHILD_BACK_ARROW ].width +
691         (Position) al -> al.spacing;
692 
693       sizes[ XmUbAL_CHILD_LABEL ].x = sizes[ XmUbAL_CHILD_FORWARD_ARROW ].x +
694         (Position) sizes[ XmUbAL_CHILD_FORWARD_ARROW ].width +
695         (Position) al -> al.spacing;
696 
697       break;
698 
699     case XmUbARROWS_RIGHT:
700       sizes[ XmUbAL_CHILD_LABEL ].x = (Position) al -> al.margin_width;
701 
702       sizes[ XmUbAL_CHILD_BACK_ARROW ].x = sizes[ XmUbAL_CHILD_LABEL ].x +
703         (Position) sizes[ XmUbAL_CHILD_LABEL ].width +
704         (Position) al -> al.spacing;
705 
706       sizes[ XmUbAL_CHILD_FORWARD_ARROW ].x =
707         sizes[ XmUbAL_CHILD_BACK_ARROW ].x +
708         (Position) sizes[ XmUbAL_CHILD_BACK_ARROW ].width +
709         (Position) al -> al.spacing;
710 
711       break;
712 
713     case XmUbARROWS_SPREAD_OUT:
714       sizes[ XmUbAL_CHILD_BACK_ARROW ].x = (Position) al -> al.margin_width;
715 
716       sizes[ XmUbAL_CHILD_LABEL ].x = sizes[ XmUbAL_CHILD_BACK_ARROW ].x +
717         (Position) sizes[ XmUbAL_CHILD_BACK_ARROW ].width +
718         (Position) al -> al.spacing;
719 
720       sizes[ XmUbAL_CHILD_FORWARD_ARROW ].x = sizes[ XmUbAL_CHILD_LABEL ].x +
721         (Position) sizes[ XmUbAL_CHILD_LABEL ].width +
722         (Position) al -> al.spacing;
723 
724       break;
725 
726   } /* switch */
727 
728 
729   /* Vertical positions. */
730   max_height = 0;
731   for( index = XmUbAL_FIRST_CHILD; index < NO_INTERNAL_CHILDREN; index ++ ){
732     if( sizes[ index ].height > max_height )
733       max_height = sizes[ index ].height;
734   }
735 
736   for( index = XmUbAL_FIRST_CHILD; index < NO_INTERNAL_CHILDREN; index ++ )
737     sizes[ index ].y = (Position) ( max_height - sizes[ index ].height ) / 2;
738 
739   /* Configure the children. */
740   /* All positions and dimensions are now in the sizes array. */
741   for( index = XmUbAL_FIRST_CHILD; index < NO_INTERNAL_CHILDREN; index ++ ){
742 
743     kid = al -> al.internal_children[ index ];
744 
745     if( ( kid != NULL ) && XtIsManaged( kid ) )
746       XtConfigureWidget( kid, sizes[ index ].x, sizes[ index ].y,
747         sizes[ index ].width, sizes[ index ].height,
748         kid -> core.border_width );
749   }
750 
751 
752   return;
753 
754 } /* DoLayout */
755 
756 
757 /*----------------------------------------------------------------------*/
758 
759 static XtGeometryResult
GeometryManager(Widget widget,XtWidgetGeometry * request,XtWidgetGeometry * reply)760   GeometryManager( Widget            widget,
761                    XtWidgetGeometry  *request,
762                    XtWidgetGeometry  *reply )
763 {
764 
765   XmUbArrowLabelWidget  al;
766   XtWidgetGeometry      own_request;
767   Dimension             old_width, old_height;
768   Dimension             pref_height;
769   Dimension             pref_width;
770   KidDimensionRec       kids_sizes[ NO_INTERNAL_CHILDREN ];
771   XtGeometryResult      result;
772 
773   /* Code. */
774 
775   al = (XmUbArrowLabelWidget) XtParent( widget );
776 
777   /* Find out how big the widget would be if the resize were allowed. */
778   GetChildPrefSizes( al, NULL, request, kids_sizes );
779   GetOwnPreferredSize( al, kids_sizes, &pref_width, &pref_height );
780 
781   /* If no change in dimensions, allow the request. */
782   if( ( pref_width == al -> core.width ) &&
783       ( pref_height == al -> core.height )){
784     DoLayout( al, kids_sizes );
785     return XtGeometryYes;
786   }
787 
788   /* We must ask our parent to resize us. */
789   own_request.request_mode = CWWidth | CWHeight;
790   own_request.width  = pref_width;
791   own_request.height = pref_height;
792 
793   /* Save dimensions. */
794   old_width  = al -> core.width;
795   old_height = al -> core.height;
796 
797   al -> al.resize_called = False;
798 
799   /* We are not interested in any compromise geometry. */
800   result = XtMakeGeometryRequest( (Widget) al, &own_request, NULL );
801 
802   /* Reset to old dimensions if request not granted. */
803   if( result != XtGeometryYes ){
804     al -> core.width  = old_width;
805     al -> core.height = old_height;
806 
807   } else {
808     if( !al -> al.resize_called )
809       Resize( (Widget) al );
810   }
811 
812 /* !!!!!!!!!!!!!!!!!!!!!! */
813   /* Always grant child's request. */
814   return XtGeometryYes;
815 
816 } /* GeometryManager */
817 
818 
819 /*----------------------------------------------------------------------*/
820 
821 static void
GetChildPrefSizes(XmUbArrowLabelWidget al,Widget initiator,XtWidgetGeometry * request,KidDimensionRec sizes[])822   GetChildPrefSizes( XmUbArrowLabelWidget  al,
823                      Widget                initiator,
824                      XtWidgetGeometry      *request,
825                      KidDimensionRec       sizes[] )
826 {
827   /* Variables. */
828   XtWidgetGeometry  desired;
829   int               index;
830   Widget            kid;
831 
832   /* Code. */
833 
834   /* Initialize. */
835   for( index = 0; index < NO_INTERNAL_CHILDREN; index ++ ){
836     sizes[ index ].width  = 0;
837     sizes[ index ].height = 0;
838     sizes[ index ].x      = 0;
839     sizes[ index ].y      = 0;
840   }
841 
842   /* Get the preferred sizes for the children. */
843   for( index = XmUbAL_FIRST_CHILD; index < NO_INTERNAL_CHILDREN; index ++ ){
844 
845     kid = al -> al.internal_children[ index ];
846 
847     if( ( kid != NULL ) && XtIsManaged( kid ) ){
848 
849       KidsPreferredGeometry( kid, initiator, request, &desired );
850 
851       sizes[ index ].width  = desired.width;
852       sizes[ index ].height = desired.height;
853 
854     }
855 
856   } /* for */
857 
858 
859   return;
860 
861 } /* GetChildPrefSizes */
862 
863 
864 /*----------------------------------------------------------------------*/
865 
866 static void
GetOwnPreferredSize(XmUbArrowLabelWidget al,KidDimensionRec sizes[],Dimension * pref_width,Dimension * pref_height)867   GetOwnPreferredSize( XmUbArrowLabelWidget  al,
868                        KidDimensionRec       sizes[],
869                        Dimension             *pref_width,
870                        Dimension             *pref_height )
871 {
872   /* Code. */
873 
874   /* All layouts arrange the widgets horizontally, so calculating the
875      preferred size is simple. */
876 
877   *pref_width = sizes[ XmUbAL_CHILD_BACK_ARROW ].width +
878                 sizes[ XmUbAL_CHILD_FORWARD_ARROW ].width +
879                 sizes[ XmUbAL_CHILD_LABEL ].width +
880                 2 * al -> al.margin_width +
881                 2 * al -> al.spacing;
882 
883   *pref_height = MAX( sizes[ XmUbAL_CHILD_LABEL ].height,
884                       MAX( sizes[ XmUbAL_CHILD_BACK_ARROW ].height,
885                            sizes[ XmUbAL_CHILD_FORWARD_ARROW ].height ) ) +
886                  2 * al -> al.margin_height;
887 
888   return;
889 
890 } /* GetOwnPreferredSize */
891 
892 
893 /*----------------------------------------------------------------------*/
894 
895 static void
GetValuesHook(Widget w,ArgList args,Cardinal * num_args)896   GetValuesHook( Widget    w,
897                  ArgList   args,
898                  Cardinal  *num_args )
899 {
900   /* Variables. */
901   int                   index;
902   XmUbArrowLabelWidget  al;
903 
904   /* Code. */
905 
906   al = (XmUbArrowLabelWidget) w;
907 
908   /* Copy the XmStrings. */
909   for( index = 0; index < *num_args; index ++ ){
910 
911     if( strcmp( args[ index ].name, XmNlabelString ) == 0 ){
912       * ( XmString *) ( args[ index ].value ) =
913         XmStringCopy( al -> al.label_string );
914 
915     }
916   }
917 
918 
919   return;
920 
921 } /* GetValuesHook */
922 
923 
924 /*----------------------------------------------------------------------*/
925 
926 static void
Initialize(Widget treq,Widget tnew,ArgList args,Cardinal * num_args)927   Initialize( Widget     treq,
928               Widget     tnew,
929               ArgList    args,
930               Cardinal   *num_args )
931 {
932   /* Variables. */
933   int                   index;
934   KidDimensionRec       kids_sizes[ NO_INTERNAL_CHILDREN ];
935   XmUbArrowLabelWidget  new;
936   Dimension             pref_height;
937   Dimension             pref_width;
938   XmString              xm;
939 
940   /* Code. */
941 
942   new = (XmUbArrowLabelWidget) tnew;
943 
944   /* Initialize private fields. */
945   /* Nullify all widget ids. */
946   for( index = XmUbAL_FIRST_CHILD; index < NO_INTERNAL_CHILDREN; index ++ )
947     new -> al.internal_children[ index ] = NULL;
948 
949   /* Start size if none supplied. */
950   if( new -> core.width == 0 )
951     new -> core.width = 300;
952   else
953     new -> al.recompute_width = False;
954 
955   if( new -> core.height == 0 )
956     new -> core.height = 100;
957   else
958     new -> al.recompute_height = False;
959 
960   /* Copy XmStrings. */
961   if( new -> al.label_string != NULL ){
962     xm = XmStringCopy( new -> al.label_string );
963     new -> al.label_string = xm;
964   }
965 
966 
967   /* Create the internal widgets. */
968   new -> al.internal_widgets_created = False;
969 
970   CreateInternalWidgets( new );
971 
972   new -> al.internal_widgets_created = True;
973 
974   /* Set the desired size of the widget. */
975   GetChildPrefSizes( new, NULL, NULL, kids_sizes );
976   GetOwnPreferredSize( new, kids_sizes, &pref_width, &pref_height );
977 
978   new -> core.width  = pref_width;
979   new -> core.height = pref_height;
980 
981   DoLayout( new, kids_sizes );
982 
983 
984   return;
985 
986 } /* Initialize */
987 
988 
989 /*----------------------------------------------------------------------*/
990 
991 static void
InsertChild(Widget widget)992   InsertChild( Widget  widget )
993 {
994 
995   /* Variables. */
996   Cardinal              num_params;
997   String                params[ 1 ];
998   XmUbArrowLabelWidget  al;
999 
1000   /* Code. */
1001 
1002   al = (XmUbArrowLabelWidget) XtParent( widget );
1003 
1004   /* We do not allow the application to create children. */
1005   if( al -> al.internal_widgets_created ){
1006 
1007     params[ 0 ] = XtClass( (Widget) al ) -> core_class.class_name;
1008     num_params  = 1;
1009     XtAppErrorMsg( XtWidgetToApplicationContext( widget ),
1010                    "childError", "number", "WidgetError",
1011                    "Applications cannot add children to %s widgets.",
1012                    params, &num_params );
1013   }
1014 
1015   /* This is an internal child. Adding it is OK. */
1016   (* ( (CompositeWidgetClass) (xmUbArrowLabelWidgetClass ->
1017      core_class.superclass) ) -> composite_class.insert_child ) ( widget );
1018 
1019 
1020   return;
1021 
1022 } /* InsertChild */
1023 
1024 
1025 /*----------------------------------------------------------------------*/
1026 
1027 static void
KidsPreferredGeometry(Widget kid,Widget initiator,XtWidgetGeometry * request,XtWidgetGeometry * desired)1028   KidsPreferredGeometry( Widget            kid,
1029                          Widget            initiator,
1030                          XtWidgetGeometry  *request,
1031                          XtWidgetGeometry  *desired )
1032 {
1033 
1034   /* Code. */
1035 
1036   if( ( kid == initiator ) && ( request != NULL ) ){
1037     /* The initiator should not be queried. */
1038     if( request -> request_mode & CWWidth )
1039       desired -> width = request -> width;
1040     else
1041       desired -> width = (Dimension) kid -> core.width;
1042 
1043     if( request -> request_mode & CWHeight )
1044       desired -> height = request -> height;
1045     else
1046       desired -> height = (Dimension) kid -> core.height;
1047 
1048   } else
1049     (void) XtQueryGeometry( kid, NULL, desired );
1050 
1051 
1052   return;
1053 
1054 } /* KidsPreferredGeometry */
1055 
1056 
1057 /*----------------------------------------------------------------------*/
1058 
1059 static void
Resize(Widget widget)1060   Resize( Widget    widget )
1061 {
1062   /* Variables. */
1063   KidDimensionRec       kids_sizes[ NO_INTERNAL_CHILDREN ];
1064   XmUbArrowLabelWidget  al;
1065 
1066   /* Code. */
1067 
1068   al = (XmUbArrowLabelWidget) widget;
1069 
1070   al -> al.resize_called = True;
1071 
1072   /* We have to get the preferred size of the children before we organize
1073      the layout. */
1074   GetChildPrefSizes( al, NULL, NULL, kids_sizes );
1075   DoLayout( al, kids_sizes );
1076 
1077 
1078   return;
1079 
1080 } /* Resize */
1081 
1082 
1083 /*----------------------------------------------------------------------*/
1084 
1085 static Boolean
ResizeIfNeeded(XmUbArrowLabelWidget al,KidDimensionRec sizes[])1086   ResizeIfNeeded( XmUbArrowLabelWidget  al,
1087                   KidDimensionRec       sizes[] )
1088 {
1089 
1090   /* Variables. */
1091   Boolean           layout_done;
1092   Dimension         pref_height;
1093   Dimension         pref_width;
1094   XtWidgetGeometry  request;
1095   XtGeometryResult  result;
1096 
1097   /* Code. */
1098 
1099   /* Initialize. */
1100   layout_done = False;
1101 
1102   /* Get the preferred dimensions of the widget. */
1103   GetChildPrefSizes( al, NULL, NULL, sizes );
1104   GetOwnPreferredSize( al, sizes, &pref_width, &pref_height );
1105 
1106   /* If we want the same dimensions, no resizing is needed. */
1107   if(( pref_width  == al -> core.width ) &&
1108      ( pref_height == al -> core.height ))
1109     return False;
1110 
1111   /* Dimensions are different. Try to resize. */
1112   request.request_mode = CWWidth | CWHeight;
1113 
1114   request.width  = pref_width;
1115   request.height = pref_height;
1116 
1117   al -> al.resize_called = False;
1118 
1119   do {
1120 
1121     result = XtMakeGeometryRequest( (Widget) al, &request, &request );
1122 
1123   } while( result == XtGeometryAlmost );
1124 
1125   if( result == XtGeometryNo )
1126     return False;
1127 
1128   /* Resize done. Core fields have already been updated. */
1129   return( al -> al.resize_called );
1130 
1131 } /* ResizeIfNeeded */
1132 
1133 
1134 /*----------------------------------------------------------------------*/
1135 
1136 static XtGeometryResult
QueryGeometry(Widget widget,XtWidgetGeometry * proposed,XtWidgetGeometry * answer)1137   QueryGeometry( Widget             widget,
1138                  XtWidgetGeometry  *proposed,
1139                  XtWidgetGeometry  *answer )
1140 {
1141 
1142   KidDimensionRec       kids_sizes[ NO_INTERNAL_CHILDREN ];
1143   XmUbArrowLabelWidget  al;
1144   Dimension             pref_height;
1145   Dimension             pref_width;
1146 
1147   /* Code. */
1148 
1149   al = (XmUbArrowLabelWidget) widget;
1150 
1151   /* Get dimensions that we *really* want. */
1152   GetChildPrefSizes( al, NULL, NULL, kids_sizes );
1153   GetOwnPreferredSize( al, kids_sizes, &pref_width, &pref_height );
1154 
1155   answer -> request_mode = CWWidth | CWHeight;
1156   answer -> width  = pref_width;
1157   answer -> height = pref_height;
1158 
1159 
1160   if( proposed == NULL ){
1161     /* This is a query for the requested geometry. */
1162 
1163     if(( answer -> height == (int) al -> core.height ) &&
1164        ( answer -> width  == (int) al -> core.width ))
1165       return XtGeometryNo;
1166     else
1167       return XtGeometryAlmost;
1168   }
1169 
1170   /* The parent supplied a geometry suggestion. */
1171   if(( answer -> height == proposed -> height ) &&
1172      ( answer -> width  == proposed -> width ))
1173     return XtGeometryYes;
1174 
1175   if( ( proposed -> height <= 1 ) ||
1176       ( proposed -> width  <= 1 ) )
1177     /* That's too small ! */
1178     return XtGeometryNo;
1179 
1180 
1181   /* Only a compromise left. */
1182   return XtGeometryAlmost;
1183 
1184 } /* QueryGeometry */
1185 
1186 
1187 /*----------------------------------------------------------------------*/
1188 
1189 static Boolean
SetValues(Widget current,Widget request,Widget new,ArgList args,Cardinal * num_args)1190   SetValues( Widget     current,
1191              Widget     request,
1192              Widget     new,
1193              ArgList    args,
1194              Cardinal   *num_args )
1195 {
1196 #ifdef Differs
1197 #undef Differs
1198 #endif
1199 
1200 #define Differs( field )  ( curW -> field != newW -> field )
1201 
1202   /* Variables. */
1203   XmUbArrowLabelWidget  curW;
1204   Arg                   local_args[ 4 ];
1205   Cardinal              n;
1206   XmUbArrowLabelWidget  newW;
1207   Boolean               visual_changed = False;
1208   XmString              xm;
1209 
1210   /* Code. */
1211 
1212   curW = (XmUbArrowLabelWidget) current;
1213   newW = (XmUbArrowLabelWidget) new;
1214 
1215   /* Width and height. */
1216   /* Resizing is handled higher up. */
1217 
1218   if( Differs( al.recompute_width ) && newW -> al.recompute_width )
1219     visual_changed = True;
1220   else if( Differs( core.width ) )
1221     newW -> al.recompute_width = False;
1222 
1223   if( Differs( al.recompute_height ) && newW -> al.recompute_height )
1224     visual_changed = True;
1225   else if( Differs( core.height ) )
1226     newW -> al.recompute_height = False;
1227 
1228   /* Margins and spacings. */
1229   if( Differs( al.margin_width )  ||
1230       Differs( al.margin_height ) ||
1231       Differs( al.spacing ) )
1232     visual_changed = True;
1233 
1234   /* These resources may only be set at creation. */
1235   if( Differs( al.arrow_orientation ) ){
1236     WarningNoResourceChange( newW, "XmUbNalArrowOrientation" );
1237     newW -> al.arrow_orientation = curW -> al.arrow_orientation;
1238   }
1239   if( Differs( al.arrow_placement ) ){
1240     WarningNoResourceChange( newW, "XmUbNalArrowPlacement" );
1241     newW -> al.arrow_placement = curW -> al.arrow_placement;
1242   }
1243 
1244   /* These resources affect child widgets. */
1245   if( Differs( al.label_string ) ||
1246       Differs( manager.foreground ) ||
1247       Differs( core.background_pixel ) ){
1248 
1249     n = 0;
1250     if( Differs( manager.foreground ) ){
1251       XtSetArg( local_args[ n ], XmNforeground,
1252                                  newW -> manager.foreground ); n++;
1253     }
1254     if( Differs( core.background_pixel ) ){
1255       XtSetArg( local_args[ n ], XmNbackground,
1256                                  newW -> core.background_pixel ); n++;
1257     }
1258 
1259     if( n != 0 ){
1260       XtSetValues( newW -> al.internal_children[ XmUbAL_CHILD_BACK_ARROW ],
1261                    local_args, n );
1262       XtSetValues( newW -> al.internal_children[ XmUbAL_CHILD_FORWARD_ARROW ],
1263                    local_args, n );
1264     }
1265 
1266     /* The label is also affected by a label string change. */
1267     if( Differs( al.label_string ) ){
1268       if( curW -> al.label_string != NULL )
1269         XmStringFree( curW -> al.label_string );
1270 
1271       if( newW -> al.label_string != NULL ){
1272         xm = XmStringCopy( newW -> al.label_string );
1273         newW -> al.label_string = xm;
1274       }
1275 
1276       XtSetArg( local_args[ n ], XmNlabelString,
1277                                  newW -> al.label_string ); n++;
1278     }
1279 
1280     if( n != 0 )
1281       XtSetValues( newW -> al.internal_children[ XmUbAL_CHILD_LABEL ],
1282                    local_args, n );
1283   }
1284 
1285 
1286   if( visual_changed ){
1287 
1288     KidDimensionRec  kids_sizes[ NO_INTERNAL_CHILDREN ];
1289     Boolean          resized;
1290 
1291     /* Code. */
1292 
1293     resized = ResizeIfNeeded( newW, kids_sizes );
1294 
1295     /* If the widget was resized, the layout has already been done. */
1296     if( !resized )
1297       DoLayout( newW, kids_sizes );
1298 
1299   }
1300 
1301   return( visual_changed );
1302 
1303 #undef Differs
1304 
1305 } /* SetValues */
1306 
1307 
1308 /*----------------------------------------------------------------------*/
1309 
1310 static void
WarningNoResourceChange(XmUbArrowLabelWidget al,String resource)1311   WarningNoResourceChange( XmUbArrowLabelWidget  al,
1312                            String                resource )
1313 {
1314   /* Variables. */
1315   Cardinal  num_params;
1316   String    params[ 2 ];
1317 
1318   /* Code. */
1319 
1320   params[ 0 ] = resource;
1321   params[ 1 ] = XtClass( al ) -> core_class.class_name;
1322   num_params  = 2;
1323   XtAppWarningMsg( XtWidgetToApplicationContext( (Widget) al ),
1324 		   "resourceError", "setValues", "WidgetError",
1325 		   "Resource %s may not be changed in %s widgets.",
1326 		   params, &num_params );
1327 
1328   return;
1329 
1330 } /* WarningNoResourceChange */
1331 
1332 
1333 /*----------------------------------------------------------------------*/
1334 
1335 Widget
XmUbCreateArrowLabel(Widget parent,String name,ArgList arglist,Cardinal argcount)1336   XmUbCreateArrowLabel( Widget    parent,
1337                         String    name,
1338                         ArgList   arglist,
1339                         Cardinal  argcount )
1340 {
1341 
1342   /* Code. */
1343 
1344   return XtCreateWidget( name, xmUbArrowLabelWidgetClass,
1345                          parent, arglist, argcount );
1346 
1347 } /* XmUbCreateArrowLabel */
1348 
1349 
1350 /*----------------------------------------------------------------------*/
1351 
1352 Widget
XmUbArrowLabelGetChild(Widget widget,int child)1353   XmUbArrowLabelGetChild( Widget  widget,
1354                           int     child )
1355 {
1356   /* Variables. */
1357   XmUbArrowLabelWidget  al;
1358 
1359   /* Code. */
1360 
1361   al = (XmUbArrowLabelWidget) widget;
1362 
1363 
1364   return( al -> al.internal_children[ child ] );
1365 
1366 } /* XmUbArrowLabelGetChild */
1367