1 /*************************************<+>*************************************
2 *****************************************************************************
8 ** Description: Code and class record for Cascade widget
10 *****************************************************************************
12 ** Copyright (c) 1988 by Hewlett-Packard Company
13 ** Copyright (c) 1988 by the Massachusetts Institute of Technology
15 ** Permission to use, copy, modify, and distribute this software
16 ** and its documentation for any purpose and without fee is hereby
17 ** granted, provided that the above copyright notice appear in all
18 ** copies and that both that copyright notice and this permission
19 ** notice appear in supporting documentation, and that the names of
20 ** Hewlett-Packard or M.I.T. not be used in advertising or publicity
21 ** pertaining to distribution of the software without specific, written
24 *****************************************************************************
25 *************************************<+>*************************************/
28 #include <X11/IntrinsicP.h>
29 #include <X11/Xutil.h>
30 #include <X11/StringDefs.h>
31 #include <X11/Xatom.h>
32 #include <X11/Shell.h>
35 #include <Xw/CascadeP.h>
36 #include <Xw/Cascade.h>
37 #include <Xw/MenuBtnP.h>
38 #include <Xw/MenuBtn.h>
41 static void Initialize();
42 static void Realize();
44 static void Redisplay();
45 static void InsertChild();
48 static Boolean
SetValues();
49 static XtGeometryResult
GeometryManager();
50 static void ChangeManaged();
51 static void GetFontGC();
52 static void SetTitleAttributes();
53 static void Visibility();
56 /* The following are used for layout spacing */
58 #define PADDING_TO_LEFT 2
59 #define PADDING_TO_RIGHT 2
60 #define PADDING_FROM_ABOVE 2
61 #define PADDING_FROM_BELOW PADDING_FROM_ABOVE
62 #define PADDING_FOR_UNDERLINE 0 /* No longer used */
63 #define DOUBLE_LINES 4
66 /****************************************************************
68 * Default translation table for class: MenuPane manager
70 ****************************************************************/
72 static char defaultTranslations
[] =
73 "<Btn1Down>: select()\n\
74 <Visible>: visible()\n\
76 <LeaveWindow>: leave()";
79 /****************************************************************
81 * Action list for class: MenuPane manager
83 ****************************************************************/
85 static XtActionsRec actionsList
[] = {
86 {"select", (XtActionProc
) Select
},
87 {"visible", (XtActionProc
) Visibility
},
88 {"unmap", (XtActionProc
) Unmap
},
89 {"leave", (XtActionProc
) Leave
},
93 /****************************************************************
97 ****************************************************************/
99 static XtResource resources
[] = {
100 {XtNtitlePosition
, XtCTitlePosition
, XtRTitlePositionType
, sizeof(int),
101 XtOffset(XwCascadeWidget
, cascade
.titlePosition
),XtRString
,"top"},
105 /****************************************************************
107 * Full class record constant
109 ****************************************************************/
111 XwCascadeClassRec XwcascadeClassRec
= {
113 /* core_class fields */
114 /* superclass */ (WidgetClass
) &XwmenupaneClassRec
,
115 /* class_name */ "XwCascade",
116 /* widget_size */ sizeof(XwCascadeRec
),
117 /* class_initialize */ NULL
,
118 /* class_part_init */ NULL
,
119 /* class_inited */ FALSE
,
120 /* initialize */ Initialize
,
121 /* initialize_hook */ NULL
,
122 /* realize */ Realize
,
123 /* actions */ actionsList
,
124 /* num_actions */ XtNumber(actionsList
),
125 /* resources */ resources
,
126 /* num_resources */ XtNumber(resources
),
127 /* xrm_class */ NULLQUARK
,
128 /* compress_motion */ TRUE
,
129 /* compress_exposure */ TRUE
,
130 /* compress_enterlv */ TRUE
,
131 /* visible_interest */ FALSE
,
134 /* expose */ Redisplay
,
135 /* set_values */ SetValues
,
136 /* set_values_hook */ NULL
,
137 /* set_values_almost */ XtInheritSetValuesAlmost
,
138 /* get_values_hook */ NULL
,
139 /* accept_focus */ NULL
,
140 /* version */ XtVersion
,
141 /* PRIVATE cb list */ NULL
,
142 /* tm_table */ defaultTranslations
,
143 /* query_geometry */ NULL
,
144 /* display_accelerator */ XtInheritDisplayAccelerator
,
147 /* composite_class fields */
148 /* geometry_manager */ GeometryManager
,
149 /* change_managed */ ChangeManaged
,
150 /* insert_child */ XtInheritInsertChild
,
151 /* delete_child */ XtInheritDeleteChild
,
154 /* constraint class fields */
155 /* resources */ NULL
,
156 /* num_resources */ 0,
157 /* constraint_size */ sizeof (Boolean
),
158 /* initialize */ (XtInitProc
)XtInheritMenuPaneConstraintInit
,
160 /* set_values */ NULL
,
163 /* manager_class fields */
164 /* traversal handler */ (XwTraversalProc
)XtInheritTraversalProc
,
165 /* translations */ NULL
167 /* menu pane class - none */
168 /* setTraversalFlag */ XtInheritSetTraversalFlagProc
170 /* cascade class - none */
175 WidgetClass XwcascadeWidgetClass
= (WidgetClass
)&XwcascadeClassRec
;
178 /*************************************<->*************************************
184 * Called upon receipt of a 'select' action; simple invokes callbacks.
189 * xxxxxxxxxxxx = xxxxxxxxxxxxx
193 * xxxxxxxxxxxx = xxxxxxxxxxxxx
198 *************************************<->***********************************/
200 static void Select (w
, event
)
206 Widget parent
, grandparent
;
208 if ((parent
= XtParent(w
)) &&
209 (grandparent
= XtParent(parent
)) &&
210 (XtIsSubclass (grandparent
, XwmenumgrWidgetClass
)))
212 /* Ask the menu mgr if we should process or ignore the select */
213 if ((*((XwMenuMgrWidgetClass
)XtClass(grandparent
))->menu_mgr_class
.
214 processSelect
) (grandparent
, w
, event
) == FALSE
)
220 XtCallCallbacks (w
, XtNselect
, NULL
);
224 /*************************************<->*************************************
230 * Called upon receipt of a LeaveNotify event; this is a NOOP, whose
231 * purpose is to simply prevent us from using the LeaveNotify handler
232 * supplied by the Manager class. The Manager's action routine does
233 * an XSetInputFocus() to root, which is not what we want here.
238 * xxxxxxxxxxxx = xxxxxxxxxxxxx
242 * xxxxxxxxxxxx = xxxxxxxxxxxxx
247 *************************************<->***********************************/
249 static void Leave (w
, event
)
258 /*************************************<->*************************************
264 * Returns the minimum height and width into which the menu pane will fit.
265 * replyHeight and replyWidth are set to the minimum acceptable size.
266 * Also, the maxCascadeWidth, maxLabel and largestButtonWidth fields are
267 * set in the widget structure.
272 * xxxxxxxxxxxx = xxxxxxxxxxxxx
276 * xxxxxxxxxxxx = xxxxxxxxxxxxx
281 *************************************<->***********************************/
283 static GetIdealSize(mw
, replyWidth
, replyHeight
)
286 Dimension
*replyWidth
, *replyHeight
; /* RETURN */
290 Dimension minWidth
, minHeight
, largestButtonWidth
;
291 XwMenuButtonWidget menuButton
; /* Current button */
292 Dimension idealWidth
;
296 * First, compute the minimum width (less padding) needed for
297 * these items; include the title in these calculations.
300 minWidth
= largestButtonWidth
= 0;
301 minHeight
= mw
->manager
.highlight_thickness
<< 1;
303 if (mw
->menu_pane
.title_showing
&& !mw
->menu_pane
.title_override
)
305 if (mw
->menu_pane
.title_type
== XwSTRING
)
307 minWidth
= mw
->cascade
.title_width
+
310 largestButtonWidth
= minWidth
;
311 if (mw
->cascade
.titlePosition
& XwTOP
)
313 minHeight
+= mw
->cascade
.title_height
+
315 PADDING_FOR_UNDERLINE
+
318 if (mw
->cascade
.titlePosition
& XwBOTTOM
)
320 minHeight
+= mw
->cascade
.title_height
+
322 PADDING_FOR_UNDERLINE
+
328 minWidth
= mw
->cascade
.title_width
+
331 largestButtonWidth
= minWidth
;
332 if (mw
->cascade
.titlePosition
& XwTOP
)
334 minHeight
+= mw
->cascade
.title_height
+
336 PADDING_FOR_UNDERLINE
+
339 if (mw
->cascade
.titlePosition
& XwBOTTOM
)
341 minHeight
+= mw
->cascade
.title_height
+
343 PADDING_FOR_UNDERLINE
+
349 minWidth
+= mw
->manager
.highlight_thickness
<< 1;
353 * Determine the ideal size for each button; keep track of largest button
356 for (i
=0; i
< mw
->manager
.num_managed_children
; i
++)
358 menuButton
= (XwMenuButtonWidget
) mw
->manager
.managed_children
[i
];
361 * If we are in the middle of a geometry request from one of
362 * our children, then we need to use the ideal size of the
363 * requesting widget, instead of the current widget. Otherwise,
364 * ask the widget for its ideal size.
366 if ((Widget
) menuButton
== mw
->cascade
.georeqWidget
)
367 idealWidth
= mw
->cascade
.georeqWidth
;
368 else if (XtIsSubclass ((Widget
)menuButton
, XwmenubuttonWidgetClass
))
370 (*(((XwMenuButtonWidgetClass
)XtClass(menuButton
))->
371 menubutton_class
.idealWidthProc
))((Widget
)menuButton
, &idealWidth
);
374 idealWidth
= menuButton
->core
.width
;
376 minWidth
= Max (minWidth
, idealWidth
+
377 (mw
->manager
.highlight_thickness
<< 1) +
378 (menuButton
->core
.border_width
<< 1));
379 largestButtonWidth
= Max (largestButtonWidth
, idealWidth
);
380 minHeight
+= menuButton
->core
.height
+
381 (menuButton
->core
.border_width
<< 1);
385 /* Set up return values */
386 if (minWidth
== 0) minWidth
= 1;
387 if (minHeight
== 0) minHeight
= 1;
389 if (replyWidth
!= NULL
) *replyWidth
= minWidth
;
390 if (replyHeight
!= NULL
) *replyHeight
= minHeight
;
392 mw
->cascade
.idealHeight
= minHeight
;
393 mw
->cascade
.idealWidth
= minWidth
;
394 mw
->cascade
.largestButtonWidth
= largestButtonWidth
;
398 /*************************************<->*************************************
400 * ProcedureName (parameters)
404 * Returns the minimum height and width into which the menu pane will fit.
405 * If the current menu pane size is small than this, then FALSE is
406 * returned; else, TRUE is returned. In all cases, replyHeight and
407 * replyWidth are set to the minimum acceptable size.
412 * xxxxxxxxxxxx = xxxxxxxxxxxxx
416 * xxxxxxxxxxxx = xxxxxxxxxxxxx
421 *************************************<->***********************************/
423 static Boolean
PreferredSize(mw
, width
, height
, replyWidth
, replyHeight
)
425 Dimension width
, height
;
426 Dimension
*replyWidth
, *replyHeight
;
428 GetIdealSize(mw
, replyWidth
, replyHeight
);
430 return ((*replyWidth
<= width
) && (*replyHeight
<= height
));
434 /*************************************<->*************************************
436 * ProcedureName (parameters)
440 * This routine assumes the menu pane size has already been updated in
441 * the core record. It will simply relayout the menu buttons, to fit
442 * the new menu pane size. This is called when XtResizeWidget() is invoked,
443 * and when our own geometry manager tries to change our size because one
444 * of our children is trying to change its size.
449 * xxxxxxxxxxxx = xxxxxxxxxxxxx
453 * xxxxxxxxxxxx = xxxxxxxxxxxxx
458 *************************************<->***********************************/
460 static void Resize(mw
)
468 XwMenuButtonWidget menuButton
; /* Current button */
469 Dimension cascadeWidth
, labelX
;
472 /* Recalculate where the title string should be displayed */
473 mw
->cascade
.title_x
= ((mw
->core
.width
>> 1) +
474 mw
->manager
.highlight_thickness
) -
475 (mw
->cascade
.title_width
>> 1);
477 /* This is a two step process: first move the item, then resize it */
478 xPos
= mw
->manager
.highlight_thickness
;
479 yPos
= mw
->cascade
.button_starting_loc
;
481 for (i
= 0; i
< mw
->manager
.num_managed_children
; i
++)
483 menuButton
= (XwMenuButtonWidget
) mw
->manager
.managed_children
[i
];
484 XtMoveWidget ((Widget
)menuButton
, xPos
, yPos
);
487 * The following kludge will force the widget's resize routine
488 * to always be called.
490 oldHeight
= menuButton
->core
.height
;
491 menuButton
->core
.height
= 0;
492 menuButton
->core
.width
= 0;
494 XtResizeWidget ((Widget
)menuButton
,
495 mw
->cascade
.largestButtonWidth
,
497 menuButton
->core
.border_width
);
499 yPos
+= menuButton
->core
.height
+
500 (menuButton
->core
.border_width
<< 1);
503 SetTitleAttributes (mw
, FALSE
);
507 /*************************************<->*************************************
509 * TryNewLayout (parameters)
513 * This determines if the menu pane needs to change size. If it needs to
514 * get bigger, then it will ask its parent's geometry manager; if this
515 * succeeds, then the menu pane window will be resized (NOTE: the menu
516 * buttons are not touched yet). Also, if our resize request succeeded,
517 * the our parent's geometry manager will have updated our size fields
518 * in our core structure. This is called during a Change Manage request,
519 * and when one of our children issues a geometry request.
521 * NOTE: menu panes ALWAYS use their 'preferred' size.
526 * xxxxxxxxxxxx = xxxxxxxxxxxxx
530 * xxxxxxxxxxxx = xxxxxxxxxxxxx
535 *************************************<->***********************************/
537 static Boolean
TryNewLayout(mw
)
540 XtWidgetGeometry request
, reply
;
543 if ((mw
->core
.width
== mw
->cascade
.idealWidth
) &&
544 (mw
->core
.height
== mw
->cascade
.idealHeight
))
551 switch (XtMakeResizeRequest ((Widget
) mw
, mw
->cascade
.idealWidth
,
552 mw
->cascade
.idealHeight
, NULL
, NULL
))
558 case XtGeometryAlmost
:
566 /*************************************<->*************************************
568 * ProcedureName (parameters)
572 * Invoked when one of our children wants to change its size. This routine
573 * will automatically update the size fields within the child's core
579 * xxxxxxxxxxxx = xxxxxxxxxxxxx
583 * xxxxxxxxxxxx = xxxxxxxxxxxxx
588 *************************************<->***********************************/
591 static XtGeometryResult
GeometryManager(w
, request
, reply
)
593 XtWidgetGeometry
*request
;
594 XtWidgetGeometry
*reply
; /* RETURN */
597 Dimension width
, height
, borderWidth
, junkH
, junkW
, newHeight
;
599 XtGeometryResult result
= XtGeometryYes
;
600 Boolean isPreferredSize
;
604 * Since the manager is solely responsible for controlling the position
605 * of its children, any geometry request made which attempts to modify
606 * the child's position will not be satified; instead, a compromise will
607 * be returned, with the position bits cleared.
609 reply
->request_mode
= 0;
611 if (request
->request_mode
& (CWX
| CWY
))
612 result
= XtGeometryAlmost
;
614 mw
= (XwCascadeWidget
) w
->core
.parent
;
617 /* Size changes must see if the new size can be accomodated */
618 if (request
->request_mode
& (CWWidth
| CWHeight
| CWBorderWidth
)) {
620 /* Make all three fields in the request valid */
621 if ((request
->request_mode
& CWWidth
) == 0)
622 request
->width
= w
->core
.width
;
623 if ((request
->request_mode
& CWHeight
) == 0)
624 request
->height
= w
->core
.height
;
625 if ((request
->request_mode
& CWBorderWidth
) == 0)
626 request
->border_width
= w
->core
.border_width
;
628 /* Set the new size within the widget */
629 width
= w
->core
.width
;
630 height
= w
->core
.height
;
631 borderWidth
= w
->core
.border_width
;
632 w
->core
.width
= request
->width
;
633 w
->core
.height
= request
->height
;
634 w
->core
.border_width
= request
->border_width
;
636 /* Calculate the new height needed to hold the menu */
637 newHeight
= mw
->core
.height
- (height
+ borderWidth
) +
638 (request
->height
+ request
->border_width
);
640 /* Let the layout routine know we are in the middle of a geo req */
641 mw
->cascade
.georeqWidget
= w
;
642 mw
->cascade
.georeqWidth
= request
->width
;
644 /* See if we can allow this size request */
645 isPreferredSize
= PreferredSize (mw
, w
->core
.width
+
646 (w
->core
.border_width
<< 1) +
647 (mw
->manager
.highlight_thickness
<< 1),
648 newHeight
, &junkW
, &junkH
);
651 mw
->cascade
.georeqWidget
= (Widget
) NULL
;
654 * Only allow an item to shrink if it was the largest item.
655 * However, always allow the item to get bigger.
658 if (!isPreferredSize
)
661 * The widget is attempting to make itself smaller than is allowed;
662 * therefore, we must return a compromise size, which we know will
665 reply
->width
= junkW
- (mw
->manager
.highlight_thickness
<< 1) -
666 (w
->core
.border_width
<< 1);
667 reply
->height
= request
->height
;
668 reply
->border_width
= request
->border_width
;
669 reply
->request_mode
= CWWidth
| CWHeight
| CWBorderWidth
;
670 result
= XtGeometryAlmost
;
672 /* Restore the previous size values */
673 w
->core
.width
= width
;
674 w
->core
.height
= height
;
675 w
->core
.border_width
= borderWidth
;
679 if (result
== XtGeometryAlmost
)
682 * Even though the size request succeeded, the request cannot
683 * be satisfied, since someone before us has already set the
684 * result to XtGeometryAlmost; most likely, it was because
685 * an attempt was made to change the X or Y values.
687 reply
->width
= request
->width
;
688 reply
->height
= request
->height
;
689 reply
->border_width
= request
->border_width
;
690 reply
->request_mode
= CWWidth
| CWHeight
| CWBorderWidth
;
692 /* Restore the previous size values */
693 w
->core
.width
= width
;
694 w
->core
.height
= height
;
695 w
->core
.border_width
= borderWidth
;
700 * All components of the geometry request could be satisfied,
701 * so make all necessary adjustments, and return a 'Yes'
702 * response to the requesting widget.
706 /* SetTitleAttributes (mw, FALSE); */
707 width
= w
->core
.width
;
708 height
= w
->core
.height
;
709 borderWidth
= w
->core
.border_width
;
710 result
= XtGeometryDone
;
713 }; /* if any size changes requested */
716 * Stacking changes are always allowed. However, if the result has
717 * already been set to XtGeometryAlmost, then some portion of the
718 * request has already failed, so we need to copy the stacking request
719 * back into the 'reply' structure, so that they are not lost.
722 if (result
== XtGeometryAlmost
)
724 if (request
->request_mode
& CWSibling
)
726 reply
->request_mode
|= CWSibling
;
727 reply
->sibling
= request
->sibling
;
730 if (request
->request_mode
& CWStackMode
)
732 reply
->request_mode
|= CWStackMode
;
733 reply
->stack_mode
= request
->stack_mode
;
741 /*************************************<->*************************************
747 * Forces the managed_children list to be updated, and then attempts to
748 * relayout the menu buttons. If the menu pane is not large enough, then
749 * it will ask its geometry manager to enlarge it. This is invoked when
750 * a new child is managed, or an existing one is unmanaged. NOTE: only
751 * managed children which also have the mapped_when_managed flag set
752 * are included in the layout calculations.
757 * xxxxxxxxxxxx = xxxxxxxxxxxxx
761 * xxxxxxxxxxxx = xxxxxxxxxxxxx
766 *************************************<->***********************************/
768 static void ChangeManaged (mw
)
771 Widget parent
, grandparent
;
774 Boolean
* managedConstraintFlag
;
776 /* Reconfigure the button box */
777 _XwSetMappedManagedChildrenList(mw
);
778 SetTitleAttributes (mw
, FALSE
);
779 GetIdealSize(mw
, NULL
, NULL
);
780 (void) TryNewLayout(mw
);
784 * Tell the menu manager that the list of mapped & managed children
787 if ((parent
= XtParent(mw
)) &&
788 (grandparent
= XtParent(parent
)) &&
789 (XtIsSubclass (grandparent
, XwmenumgrWidgetClass
)))
791 (*((XwMenuMgrWidgetClass
)XtClass(grandparent
))->menu_mgr_class
.
792 paneManagedChildren
) (grandparent
, (Widget
)mw
);
796 * The constraint record has been updated by the menu manager.
801 /*************************************<->*************************************
808 * Initialize the menu_pane fields within the widget's instance structure.
809 * Calls for registering the pane with a menu manager, and for attaching
810 * the pane to a menu button are handled by our meta class.
815 * xxxxxxxxxxxx = xxxxxxxxxxxxx
819 * xxxxxxxxxxxx = xxxxxxxxxxxxx
824 *************************************<->***********************************/
826 static void Initialize (request
, new)
827 XwCascadeWidget request
, new;
831 new->cascade
.georeqWidget
= (Widget
) NULL
;
833 /* Determine the title attributes, and the starting location for our kids */
834 SetTitleAttributes (new, TRUE
);
836 /* Force our parent shell to be resizable */
837 XtSetArg (args2
[0], XtNallowShellResize
, TRUE
);
838 XtSetArg (args2
[1], XtNoverrideRedirect
, TRUE
);
839 XtSetValues (new->core
.parent
, args2
, XtNumber(args2
));
841 /* Augment our translations to include the traversal actions */
842 XtAugmentTranslations ((Widget
) new,
843 XwmanagerClassRec
.manager_class
.translations
);
845 /* KLUDGE!!! This is necessary!!! The shell must be realized so
846 * that the cascades changed_managed routine is called and the
847 * keyboard accelerators are set up for the menu manager.
849 if (new->core
.height
> 0)
850 (new->core
.parent
)->core
.height
= new->core
.height
;
852 (new->core
.parent
)->core
.height
= 1;
854 if (new->core
.width
> 0)
855 (new->core
.parent
)->core
.width
= new->core
.width
;
857 (new->core
.parent
)->core
.width
= 1;
859 if (XtIsSubclass(new->core
.parent
, shellWidgetClass
))
860 XtRealizeWidget (new->core
.parent
);
863 /*************************************<->*************************************
869 * Invoked only when the menu pane is realized. It will create the window
870 * in which the menu pane will be displayed.
875 * xxxxxxxxxxxx = xxxxxxxxxxxxx
879 * xxxxxxxxxxxx = xxxxxxxxxxxxx
884 *************************************<->***********************************/
886 static void Realize(w
, p_valueMask
, attributes
)
889 XSetWindowAttributes
*attributes
;
892 Mask valueMask
= *p_valueMask
;
894 attributes
->bit_gravity
= ForgetGravity
;
895 valueMask
|= CWBitGravity
;
896 mw
= (XwCascadeWidget
) w
;
899 XCreateWindow(XtDisplay(w
), w
->core
.parent
->core
.window
,
900 w
->core
.x
, w
->core
.y
, w
->core
.width
, w
->core
.height
,
901 w
->core
.border_width
, w
->core
.depth
,
902 InputOutput
, (Visual
*)CopyFromParent
,
903 valueMask
, attributes
);
909 /*************************************<->*************************************
919 * xxxxxxxxxxxx = xxxxxxxxxxxxx
923 * xxxxxxxxxxxx = xxxxxxxxxxxxx
928 *************************************<->***********************************/
930 static Boolean
SetValues (current
, request
, new)
931 XwCascadeWidget current
, request
, new;
933 Boolean redrawFlag
= FALSE
;
936 * We never allow our traversal flags to be changed during SetValues();
937 * this is enforced by our superclass.
940 /* Validate the title position, and see if it has changed */
942 if ((new->cascade
.titlePosition
& (XwTOP
| XwBOTTOM
)) == 0)
944 new->cascade
.titlePosition
= current
->cascade
.titlePosition
;
946 "Cascade: Invalid title position; resetting to previous setting");
949 if ((current
->cascade
.titlePosition
& (XwTOP
| XwBOTTOM
)) !=
950 (new->cascade
.titlePosition
& (XwTOP
| XwBOTTOM
)))
956 SetTitleAttributes (new, FALSE
);
957 GetIdealSize(new, NULL
, NULL
);
958 new->core
.height
= new->cascade
.idealHeight
;
959 new->core
.width
= new->cascade
.idealWidth
;
962 * If the title position changes, but the size of the menupane
963 * does not (because no other attributes have changed which could
964 * cause the size to change), then we need to force a call to our
965 * resize() procedure, so that the menu buttons get repositioned
966 * relative to the new title position.
968 if (redrawFlag
&& (new->core
.height
== current
->core
.height
) &&
969 (new->core
.width
== current
->core
.width
))
978 /*************************************<->*************************************
988 * xxxxxxxxxxxx = xxxxxxxxxxxxx
992 * xxxxxxxxxxxx = xxxxxxxxxxxxx
997 *************************************<->***********************************/
999 static void Redisplay (w
, event
)
1003 XwCascadeWidget mw
= (XwCascadeWidget
) w
;
1005 /* If a title is defined, then redisplay it, if 'showing' flag set */
1006 if (mw
->menu_pane
.title_showing
&& ! mw
->menu_pane
.title_override
)
1009 /* Recalculate the title position */
1010 mw
->cascade
.title_x
= (mw
->core
.width
>> 1) +
1011 mw
->manager
.highlight_thickness
-
1012 (mw
->cascade
.title_width
>> 1);
1014 if (mw
->menu_pane
.title_type
== XwSTRING
)
1016 if (mw
->cascade
.titlePosition
& XwTOP
)
1018 XDrawString (XtDisplay(w
), XtWindow(w
), mw
->menu_pane
.titleGC
,
1019 mw
->cascade
.title_x
, mw
->cascade
.top_title_y
,
1020 mw
->menu_pane
.title_string
,
1021 XwStrlen(mw
->menu_pane
.title_string
));
1023 XDrawLine (XtDisplay(w
), XtWindow(w
), mw
->menu_pane
.titleGC
, 0,
1024 mw
->cascade
.top_title_y
+
1025 mw
->menu_pane
.title_font
->descent
+
1026 PADDING_FOR_UNDERLINE
+ 1,
1028 mw
->cascade
.top_title_y
+
1029 mw
->menu_pane
.title_font
->descent
+
1030 PADDING_FOR_UNDERLINE
+ 1);
1032 XDrawLine (XtDisplay(w
), XtWindow(w
), mw
->menu_pane
.titleGC
, 0,
1033 mw
->cascade
.top_title_y
+
1034 mw
->menu_pane
.title_font
->descent
+
1035 PADDING_FOR_UNDERLINE
+ 3,
1037 mw
->cascade
.top_title_y
+
1038 mw
->menu_pane
.title_font
->descent
+
1039 PADDING_FOR_UNDERLINE
+ 3);
1042 if (mw
->cascade
.titlePosition
& XwBOTTOM
)
1044 XDrawString (XtDisplay(w
), XtWindow(w
), mw
->menu_pane
.titleGC
,
1045 mw
->cascade
.title_x
, mw
->cascade
.bottom_title_y
,
1046 mw
->menu_pane
.title_string
,
1047 XwStrlen(mw
->menu_pane
.title_string
));
1049 XDrawLine (XtDisplay(w
), XtWindow(w
), mw
->menu_pane
.titleGC
, 0,
1050 mw
->cascade
.bottom_title_y
-
1051 mw
->menu_pane
.title_font
->ascent
-
1054 mw
->cascade
.bottom_title_y
-
1055 mw
->menu_pane
.title_font
->ascent
-
1058 XDrawLine (XtDisplay(w
), XtWindow(w
), mw
->menu_pane
.titleGC
, 0,
1059 mw
->cascade
.bottom_title_y
-
1060 mw
->menu_pane
.title_font
->ascent
-
1063 mw
->cascade
.bottom_title_y
-
1064 mw
->menu_pane
.title_font
->ascent
-
1068 else if (mw
->menu_pane
.titleImage
)
1070 if (mw
->cascade
.titlePosition
& XwTOP
)
1072 XPutImage (XtDisplay(mw
), XtWindow(mw
), mw
->menu_pane
.titleGC
,
1073 mw
->menu_pane
.titleImage
, 0, 0,
1074 mw
->cascade
.title_x
, mw
->cascade
.top_title_y
,
1075 mw
->cascade
.title_width
, mw
->cascade
.title_height
);
1077 XDrawLine (XtDisplay(w
), XtWindow(w
), mw
->menu_pane
.titleGC
, 0,
1078 mw
->cascade
.top_title_y
+
1079 mw
->cascade
.title_height
+
1080 PADDING_FOR_UNDERLINE
+ 1,
1082 mw
->cascade
.top_title_y
+
1083 mw
->cascade
.title_height
+
1084 PADDING_FOR_UNDERLINE
+ 1);
1086 XDrawLine (XtDisplay(w
), XtWindow(w
), mw
->menu_pane
.titleGC
, 0,
1087 mw
->cascade
.top_title_y
+
1088 mw
->cascade
.title_height
+
1089 PADDING_FOR_UNDERLINE
+ 3,
1091 mw
->cascade
.top_title_y
+
1092 mw
->cascade
.title_height
+
1093 PADDING_FOR_UNDERLINE
+ 3);
1096 if (mw
->cascade
.titlePosition
& XwBOTTOM
)
1098 XPutImage (XtDisplay(mw
), XtWindow(mw
), mw
->menu_pane
.titleGC
,
1099 mw
->menu_pane
.titleImage
, 0, 0,
1100 mw
->cascade
.title_x
, mw
->cascade
.bottom_title_y
,
1101 mw
->cascade
.title_width
, mw
->cascade
.title_height
);
1103 XDrawLine (XtDisplay(w
), XtWindow(w
), mw
->menu_pane
.titleGC
, 0,
1104 mw
->cascade
.bottom_title_y
-
1107 mw
->cascade
.bottom_title_y
-
1110 XDrawLine (XtDisplay(w
), XtWindow(w
), mw
->menu_pane
.titleGC
, 0,
1111 mw
->cascade
.bottom_title_y
-
1114 mw
->cascade
.bottom_title_y
-
1123 /*************************************<->*************************************
1125 * SetTitleAttributes
1129 * This procedure calculates the height, width, and starting location
1130 * for the title string/image. In addition, it uses
1131 * this information to determine where the menu buttons should be laid
1132 * out within the pane.
1137 * mw = The menu pane widget whose title attributes are being calculated.
1139 * setCoreFields = A boolean flag, indicating whether the core height
1140 * and width fields should be set to their default value.
1141 * This flag should only be set to TRUE when this routine
1142 * is invoked at initialization time; all other calls must
1143 * set this to FALSE.
1147 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1152 *************************************<->***********************************/
1154 static void SetTitleAttributes (mw
, setCoreFields
)
1157 Boolean setCoreFields
;
1161 if (mw
->menu_pane
.title_showing
&& !mw
->menu_pane
.title_override
)
1163 if (mw
->menu_pane
.title_type
== XwSTRING
)
1165 /* Determine size of title string */
1166 mw
->cascade
.title_width
= XTextWidth (mw
->menu_pane
.title_font
,
1167 mw
->menu_pane
.title_string
,
1168 XwStrlen(mw
->menu_pane
.title_string
));
1169 mw
->cascade
.title_height
= mw
->menu_pane
.title_font
->ascent
+
1170 mw
->menu_pane
.title_font
->descent
;
1171 mw
->cascade
.title_x
= PADDING_TO_LEFT
+
1172 mw
->manager
.highlight_thickness
;
1174 /* Default size should contain just the title string */
1177 mw
->core
.width
= mw
->cascade
.title_width
+
1178 (mw
->manager
.highlight_thickness
<< 1) +
1181 mw
->core
.height
= mw
->manager
.highlight_thickness
<< 1;
1182 if (mw
->cascade
.titlePosition
& XwTOP
)
1183 mw
->core
.height
+= mw
->cascade
.title_height
+
1184 PADDING_FROM_ABOVE
+
1185 PADDING_FOR_UNDERLINE
+
1187 if (mw
->cascade
.titlePosition
& XwBOTTOM
)
1188 mw
->core
.height
+= mw
->cascade
.title_height
+
1189 PADDING_FROM_BELOW
+
1190 PADDING_FOR_UNDERLINE
+
1194 if (mw
->cascade
.titlePosition
& XwTOP
)
1195 mw
->cascade
.top_title_y
= PADDING_FROM_ABOVE
+
1196 mw
->manager
.highlight_thickness
+
1197 mw
->menu_pane
.title_font
->ascent
;
1199 mw
->cascade
.top_title_y
= 0;
1201 if (mw
->cascade
.titlePosition
& XwBOTTOM
)
1202 mw
->cascade
.bottom_title_y
= mw
->core
.height
-
1203 mw
->manager
.highlight_thickness
-
1204 mw
->menu_pane
.title_font
->descent
-
1205 PADDING_FROM_ABOVE
-
1206 PADDING_FOR_UNDERLINE
;
1208 mw
->cascade
.bottom_title_y
= mw
->core
.height
-
1209 mw
->manager
.highlight_thickness
;
1211 if (mw
->cascade
.titlePosition
& XwTOP
)
1212 mw
->cascade
.button_starting_loc
= mw
->cascade
.top_title_y
+
1213 mw
->menu_pane
.title_font
->descent
+
1214 PADDING_FOR_UNDERLINE
+
1217 mw
->cascade
.button_starting_loc
= mw
->manager
.highlight_thickness
;
1219 else if (mw
->menu_pane
.titleImage
)
1221 /* Determine size of title image */
1222 mw
->cascade
.title_width
= mw
->menu_pane
.titleImage
->width
;
1223 mw
->cascade
.title_height
= mw
->menu_pane
.titleImage
->height
;
1224 mw
->cascade
.title_x
= PADDING_TO_LEFT
+
1225 mw
->manager
.highlight_thickness
;
1227 /* Default size should contain just the title image */
1230 mw
->core
.width
= mw
->cascade
.title_width
+
1231 (mw
->manager
.highlight_thickness
<< 1) +
1234 mw
->core
.height
= (mw
->manager
.highlight_thickness
<< 1);;
1235 if (mw
->cascade
.titlePosition
& XwTOP
)
1236 mw
->core
.height
+= mw
->cascade
.title_height
+
1237 PADDING_FROM_ABOVE
+
1238 PADDING_FOR_UNDERLINE
+
1240 if (mw
->cascade
.titlePosition
& XwBOTTOM
)
1241 mw
->core
.height
+= mw
->cascade
.title_height
+
1242 PADDING_FROM_ABOVE
+
1243 PADDING_FOR_UNDERLINE
+
1247 if (mw
->cascade
.titlePosition
& XwTOP
)
1248 mw
->cascade
.top_title_y
= PADDING_FROM_ABOVE
+
1249 mw
->manager
.highlight_thickness
;
1251 mw
->cascade
.top_title_y
= 0;
1252 if (mw
->cascade
.titlePosition
& XwBOTTOM
)
1253 mw
->cascade
.bottom_title_y
= mw
->core
.height
-
1254 mw
->manager
.highlight_thickness
-
1255 mw
->cascade
.title_height
-
1258 mw
->cascade
.bottom_title_y
= mw
->core
.height
-
1259 mw
->manager
.highlight_thickness
;
1261 if (mw
->cascade
.titlePosition
& XwTOP
)
1262 mw
->cascade
.button_starting_loc
= mw
->cascade
.top_title_y
+
1263 mw
->cascade
.title_height
+
1264 PADDING_FOR_UNDERLINE
+
1267 mw
->cascade
.button_starting_loc
= mw
->manager
.highlight_thickness
;
1271 /* No image is present */
1275 mw
->core
.width
= (mw
->manager
.highlight_thickness
> 0) ?
1276 (mw
->manager
.highlight_thickness
<< 1) : 2;
1277 mw
->core
.height
= mw
->core
.width
;
1279 mw
->cascade
.title_width
= 0;
1280 mw
->cascade
.title_height
= 0;
1281 mw
->cascade
.title_x
= 0;
1282 mw
->cascade
.top_title_y
= 0;
1283 mw
->cascade
.bottom_title_y
= mw
->core
.height
;
1284 mw
->cascade
.button_starting_loc
= mw
->manager
.highlight_thickness
;
1289 /* No image or string is present */
1293 mw
->core
.width
= (mw
->manager
.highlight_thickness
> 0) ?
1294 (mw
->manager
.highlight_thickness
<< 1) : 2;
1295 mw
->core
.height
= mw
->core
.width
;
1297 mw
->cascade
.title_width
= 0;
1298 mw
->cascade
.title_height
= 0;
1299 mw
->cascade
.title_x
= 0;
1300 mw
->cascade
.top_title_y
= 0;
1301 mw
->cascade
.bottom_title_y
= mw
->core
.height
;
1302 mw
->cascade
.button_starting_loc
= mw
->manager
.highlight_thickness
;
1307 /*************************************<->*************************************
1309 * Visibility(parameters)
1313 * xxxxxxxxxxxxxxxxxxxxxxx
1318 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1322 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1327 *************************************<->***********************************/
1329 static void Visibility (widget
, event
)
1336 * Noop; purpose is to prevent Manager's translation from
1342 /*************************************<->*************************************
1348 * xxxxxxxxxxxxxxxxxxxxxxx
1353 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1357 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1362 *************************************<->***********************************/
1364 static void Unmap (widget
, event
)
1371 * Noop; purpose is to prevent Manager's translation from