1 /* $XConsortium: List.c,v 1.39 94/04/17 20:12:15 kaleb Exp $ */
4 Copyright (c) 1989, 1994 X Consortium
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
20 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 Except as contained in this notice, the name of the X Consortium shall not be
24 used in advertising or otherwise to promote the sale, use or other dealings
25 in this Software without prior written authorization from the X Consortium.
29 * List.c - List widget
31 * This is a List widget. It allows the user to select an item in a list and
32 * notifies the application through a callback function.
35 * By: Chris D. Peterson
43 #include <X11/IntrinsicP.h>
44 #include <X11/StringDefs.h>
46 #include <X11/Xmu/Drawing.h>
48 #include <X11/Xaw/XawInit.h>
49 #include <X11/Xaw/ListP.h>
51 /* These added so widget knows whether its height, width are user selected.
52 I also added the freedoms member of the list widget part. */
58 #define HeightFree( w ) !(((ListWidget)(w))->list.freedoms & HeightLock )
59 #define WidthFree( w ) !(((ListWidget)(w))->list.freedoms & WidthLock )
60 #define LongestFree( w ) !(((ListWidget)(w))->list.freedoms & LongestLock )
63 * Default Translation table.
66 static char defaultTranslations
[] =
70 /****************************************************************
72 * Full class record constant
74 ****************************************************************/
78 #define offset(field) XtOffset(ListWidget, field)
80 static XtResource resources
[] = {
81 {XtNforeground
, XtCForeground
, XtRPixel
, sizeof(Pixel
),
82 offset(list
.foreground
), XtRString
, XtDefaultForeground
},
83 {XtNcursor
, XtCCursor
, XtRCursor
, sizeof(Cursor
),
84 offset(simple
.cursor
), XtRString
, "left_ptr"},
85 {XtNfont
, XtCFont
, XtRFontStruct
, sizeof(XFontStruct
*),
86 offset(list
.font
),XtRString
, XtDefaultFont
},
87 {XtNfontSet
, XtCFontSet
, XtRFontSet
, sizeof(XFontSet
),
88 offset(list
.fontset
),XtRString
, XtDefaultFontSet
},
89 {XtNlist
, XtCList
, XtRPointer
, sizeof(char **),
90 offset(list
.list
), XtRString
, NULL
},
91 {XtNdefaultColumns
, XtCColumns
, XtRInt
, sizeof(int),
92 offset(list
.default_cols
), XtRImmediate
, (XtPointer
)2},
93 {XtNlongest
, XtCLongest
, XtRInt
, sizeof(int),
94 offset(list
.longest
), XtRImmediate
, (XtPointer
)0},
95 {XtNnumberStrings
, XtCNumberStrings
, XtRInt
, sizeof(int),
96 offset(list
.nitems
), XtRImmediate
, (XtPointer
)0},
97 {XtNpasteBuffer
, XtCBoolean
, XtRBoolean
, sizeof(Boolean
),
98 offset(list
.paste
), XtRImmediate
, (XtPointer
) False
},
99 {XtNforceColumns
, XtCColumns
, XtRBoolean
, sizeof(Boolean
),
100 offset(list
.force_cols
), XtRImmediate
, (XtPointer
) False
},
101 {XtNverticalList
, XtCBoolean
, XtRBoolean
, sizeof(Boolean
),
102 offset(list
.vertical_cols
), XtRImmediate
, (XtPointer
) False
},
103 {XtNinternalWidth
, XtCWidth
, XtRDimension
, sizeof(Dimension
),
104 offset(list
.internal_width
), XtRImmediate
, (XtPointer
)2},
105 {XtNinternalHeight
, XtCHeight
, XtRDimension
, sizeof(Dimension
),
106 offset(list
.internal_height
), XtRImmediate
, (XtPointer
)2},
107 {XtNcolumnSpacing
, XtCSpacing
, XtRDimension
, sizeof(Dimension
),
108 offset(list
.column_space
), XtRImmediate
, (XtPointer
)6},
109 {XtNrowSpacing
, XtCSpacing
, XtRDimension
, sizeof(Dimension
),
110 offset(list
.row_space
), XtRImmediate
, (XtPointer
)2},
111 {XtNcallback
, XtCCallback
, XtRCallback
, sizeof(XtPointer
),
112 offset(list
.callback
), XtRCallback
, NULL
},
115 static void Initialize();
116 static void ChangeSize();
117 static void Resize();
118 static void Redisplay();
119 static void Destroy();
120 static Boolean
Layout();
121 static XtGeometryResult
PreferredGeom();
122 static Boolean
SetValues();
123 static void Notify(), Set(), Unset();
125 static XtActionsRec actions
[] = {
131 ListClassRec listClassRec
= {
133 /* core_class fields */
134 /* superclass */ (WidgetClass
) &simpleClassRec
,
135 /* class_name */ "List",
136 /* widget_size */ sizeof(ListRec
),
137 /* class_initialize */ XawInitializeWidgetSet
,
138 /* class_part_initialize */ NULL
,
139 /* class_inited */ FALSE
,
140 /* initialize */ Initialize
,
141 /* initialize_hook */ NULL
,
142 /* realize */ XtInheritRealize
,
143 /* actions */ actions
,
144 /* num_actions */ XtNumber(actions
),
145 /* resources */ resources
,
146 /* num_resources */ XtNumber(resources
),
147 /* xrm_class */ NULLQUARK
,
148 /* compress_motion */ TRUE
,
149 /* compress_exposure */ FALSE
,
150 /* compress_enterleave */ TRUE
,
151 /* visible_interest */ FALSE
,
152 /* destroy */ Destroy
,
154 /* expose */ Redisplay
,
155 /* set_values */ SetValues
,
156 /* set_values_hook */ NULL
,
157 /* set_values_almost */ XtInheritSetValuesAlmost
,
158 /* get_values_hook */ NULL
,
159 /* accept_focus */ NULL
,
160 /* version */ XtVersion
,
161 /* callback_private */ NULL
,
162 /* tm_table */ defaultTranslations
,
163 /* query_geometry */ PreferredGeom
,
165 /* Simple class fields initialization */
167 /* change_sensitive */ XtInheritChangeSensitive
169 /* List class fields initialization */
175 WidgetClass listWidgetClass
= (WidgetClass
)&listClassRec
;
177 /****************************************************************
181 ****************************************************************/
183 static void GetGCs(w
)
187 ListWidget lw
= (ListWidget
) w
;
189 values
.foreground
= lw
->list
.foreground
;
190 values
.font
= lw
->list
.font
->fid
;
192 if ( lw
->simple
.international
== True
)
193 lw
->list
.normgc
= XtAllocateGC( w
, 0, (unsigned) GCForeground
,
194 &values
, GCFont
, 0 );
196 lw
->list
.normgc
= XtGetGC( w
, (unsigned) GCForeground
| GCFont
,
199 values
.foreground
= lw
->core
.background_pixel
;
201 if ( lw
->simple
.international
== True
)
202 lw
->list
.revgc
= XtAllocateGC( w
, 0, (unsigned) GCForeground
,
203 &values
, GCFont
, 0 );
205 lw
->list
.revgc
= XtGetGC( w
, (unsigned) GCForeground
| GCFont
,
208 values
.tile
= XmuCreateStippledPixmap(XtScreen(w
),
210 lw
->core
.background_pixel
,
212 values
.fill_style
= FillTiled
;
214 if ( lw
->simple
.international
== True
)
215 lw
->list
.graygc
= XtAllocateGC( w
, 0, (unsigned) GCTile
| GCFillStyle
,
216 &values
, GCFont
, 0 );
218 lw
->list
.graygc
= XtGetGC( w
, (unsigned) GCFont
| GCTile
| GCFillStyle
,
223 /* CalculatedValues()
225 * does routine checks/computations that must be done after data changes
226 * but won't hurt if accidently called
228 * These calculations were needed in SetValues. They were in ResetList.
229 * ResetList called ChangeSize, which made an XtGeometryRequest. You
230 * MAY NOT change your geometry from within a SetValues. (Xt man,
231 * sect. 9.7.2) So, I factored these changes out. */
233 static void CalculatedValues( w
)
238 ListWidget lw
= (ListWidget
) w
;
240 /* If list is NULL then the list will just be the name of the widget. */
242 if (lw
->list
.list
== NULL
) {
243 lw
->list
.list
= &(lw
->core
.name
);
247 /* Get number of items. */
249 if (lw
->list
.nitems
== 0)
250 for ( ; lw
->list
.list
[lw
->list
.nitems
] != NULL
; lw
->list
.nitems
++);
252 /* Get column width. */
254 if ( LongestFree( lw
) ) {
256 lw
->list
.longest
= 0; /* so it will accumulate real longest below */
258 for ( i
= 0 ; i
< lw
->list
.nitems
; i
++) {
259 if ( lw
->simple
.international
== True
)
260 len
= XmbTextEscapement(lw
->list
.fontset
, lw
->list
.list
[i
],
261 strlen(lw
->list
.list
[i
]));
263 len
= XTextWidth(lw
->list
.font
, lw
->list
.list
[i
],
264 strlen(lw
->list
.list
[i
]));
265 if (len
> lw
->list
.longest
)
266 lw
->list
.longest
= len
;
270 lw
->list
.col_width
= lw
->list
.longest
+ lw
->list
.column_space
;
273 /* Function Name: ResetList
274 * Description: Resets the new list when important things change.
275 * Arguments: w - the widget.
276 * changex, changey - allow the height or width to change?
278 * Returns: TRUE if width or height have been changed
282 ResetList( w
, changex
, changey
)
284 Boolean changex
, changey
;
286 Dimension width
= w
->core
.width
;
287 Dimension height
= w
->core
.height
;
289 CalculatedValues( w
);
291 if( Layout( w
, changex
, changey
, &width
, &height
) )
292 ChangeSize( w
, width
, height
);
295 /* Function Name: ChangeSize.
296 * Description: Laysout the widget.
297 * Arguments: w - the widget to try change the size of.
302 ChangeSize(w
, width
, height
)
304 Dimension width
, height
;
306 XtWidgetGeometry request
, reply
;
308 request
.request_mode
= CWWidth
| CWHeight
;
309 request
.width
= width
;
310 request
.height
= height
;
312 switch ( XtMakeGeometryRequest(w
, &request
, &reply
) ) {
317 case XtGeometryAlmost
:
318 Layout(w
, (request
.height
!= reply
.height
),
319 (request
.width
!= reply
.width
),
320 &(reply
.width
), &(reply
.height
));
322 switch (XtMakeGeometryRequest(w
, &request
, &reply
) ) {
326 case XtGeometryAlmost
:
328 Layout(w
, FALSE
, FALSE
, &(request
.width
), &(request
.height
));
329 request
.request_mode
= CWWidth
| CWHeight
;
330 XtMakeGeometryRequest(w
, &request
, &reply
);
333 XtAppWarning(XtWidgetToApplicationContext(w
),
334 "List Widget: Unknown geometry return.");
339 XtAppWarning(XtWidgetToApplicationContext(w
),
340 "List Widget: Unknown geometry return.");
345 /* Function Name: Initialize
346 * Description: Function that initilizes the widget instance.
347 * Arguments: junk - NOT USED.
348 * new - the new widget.
354 Initialize(junk
, new, args
, num_args
)
359 ListWidget lw
= (ListWidget
) new;
362 * Initialize all private resources.
365 /* record for posterity if we are free */
366 lw
->list
.freedoms
= (lw
->core
.width
!= 0) * WidthLock
+
367 (lw
->core
.height
!= 0) * HeightLock
+
368 (lw
->list
.longest
!= 0) * LongestLock
;
372 /* Set row height. based on font or fontset */
374 if (lw
->simple
.international
== True
)
375 lw
->list
.row_height
=
376 XExtentsOfFontSet(lw
->list
.fontset
)->max_ink_extent
.height
377 + lw
->list
.row_space
;
379 lw
->list
.row_height
= lw
->list
.font
->max_bounds
.ascent
380 + lw
->list
.font
->max_bounds
.descent
381 + lw
->list
.row_space
;
383 ResetList( new, WidthFree( lw
), HeightFree( lw
) );
385 lw
->list
.highlight
= lw
->list
.is_highlighted
= NO_HIGHLIGHT
;
389 /* Function Name: CvtToItem
390 * Description: Converts Xcoord to item number of item containing that
392 * Arguments: w - the list widget.
393 * xloc, yloc - x location, and y location.
394 * Returns: the item number.
398 CvtToItem(w
, xloc
, yloc
, item
)
404 ListWidget lw
= (ListWidget
) w
;
407 if (lw
->list
.vertical_cols
) {
408 one
= lw
->list
.nrows
* ((xloc
- (int) lw
->list
.internal_width
)
409 / lw
->list
.col_width
);
410 another
= (yloc
- (int) lw
->list
.internal_height
)
411 / lw
->list
.row_height
;
412 /* If out of range, return minimum possible value. */
413 if (another
>= lw
->list
.nrows
) {
414 another
= lw
->list
.nrows
- 1;
415 ret_val
= OUT_OF_RANGE
;
419 one
= (lw
->list
.ncols
* ((yloc
- (int) lw
->list
.internal_height
)
420 / lw
->list
.row_height
)) ;
421 /* If in right margin handle things right. */
422 another
= (xloc
- (int) lw
->list
.internal_width
) / lw
->list
.col_width
;
423 if (another
>= lw
->list
.ncols
) {
424 another
= lw
->list
.ncols
- 1;
425 ret_val
= OUT_OF_RANGE
;
428 if ((xloc
< 0) || (yloc
< 0))
429 ret_val
= OUT_OF_RANGE
;
430 if (one
< 0) one
= 0;
431 if (another
< 0) another
= 0;
432 *item
= one
+ another
;
433 if (*item
>= lw
->list
.nitems
) return(OUT_OF_RANGE
);
437 /* Function Name: FindCornerItems.
438 * Description: Find the corners of the rectangle in item space.
439 * Arguments: w - the list widget.
440 * event - the event structure that has the rectangle it it.
441 * ul_ret, lr_ret - the corners ** RETURNED **.
446 FindCornerItems(w
, event
, ul_ret
, lr_ret
)
449 int *ul_ret
, *lr_ret
;
453 xloc
= event
->xexpose
.x
;
454 yloc
= event
->xexpose
.y
;
455 CvtToItem(w
, xloc
, yloc
, ul_ret
);
456 xloc
+= event
->xexpose
.width
;
457 yloc
+= event
->xexpose
.height
;
458 CvtToItem(w
, xloc
, yloc
, lr_ret
);
461 /* Function Name: ItemInRectangle
462 * Description: returns TRUE if the item passed is in the given rectangle.
463 * Arguments: w - the list widget.
464 * ul, lr - corners of the rectangle in item space.
465 * item - item to check.
466 * Returns: TRUE if the item passed is in the given rectangle.
470 ItemInRectangle(w
, ul
, lr
, item
)
474 ListWidget lw
= (ListWidget
) w
;
478 if (item
< ul
|| item
> lr
)
480 if (lw
->list
.vertical_cols
)
481 things
= lw
->list
.nrows
;
483 things
= lw
->list
.ncols
;
485 mod_item
= item
% things
;
486 if ( (mod_item
>= ul
% things
) && (mod_item
<= lr
% things
) )
492 /* HighlightBackground()
494 * Paints the color of the background for the given item. It performs
495 * clipping to the interior of internal_width/height by hand, as its a
496 * simple calculation and probably much faster than using Xlib and a clip mask.
498 * x, y - ul corner of the area item occupies.
499 * gc - the gc to use to paint this rectangle */
502 HighlightBackground( w
, x
, y
, gc
)
507 ListWidget lw
= (ListWidget
) w
;
509 /* easy to clip the rectangle by hand and probably alot faster than Xlib */
511 Dimension width
= lw
->list
.col_width
;
512 Dimension height
= lw
->list
.row_height
;
513 Dimension frame_limited_width
= w
->core
.width
- lw
->list
.internal_width
- x
;
514 Dimension frame_limited_height
= w
->core
.height
- lw
->list
.internal_height
- y
;
516 /* Clip the rectangle width and height to the edge of the drawable area */
518 if ( width
> frame_limited_width
)
519 width
= frame_limited_width
;
520 if ( height
> frame_limited_height
)
521 height
= frame_limited_height
;
523 /* Clip the rectangle x and y to the edge of the drawable area */
525 if ( x
< lw
->list
.internal_width
) {
526 width
= width
- ( lw
->list
.internal_width
- x
);
527 x
= lw
->list
.internal_width
;
529 if ( y
< lw
->list
.internal_height
) {
530 height
= height
- ( lw
->list
.internal_height
- x
);
531 y
= lw
->list
.internal_height
;
533 XFillRectangle( XtDisplay( w
), XtWindow( w
), gc
, x
, y
,
538 /* ClipToShadowInteriorAndLongest()
540 * Converts the passed gc so that any drawing done with that GC will not
541 * write in the empty margin (specified by internal_width/height) (which also
542 * prevents erasing the shadow. It also clips against the value longest.
543 * If the user doesn't set longest, this has no effect (as longest is the
544 * maximum of all item lengths). If the user does specify, say, 80 pixel
545 * columns, though, this prevents items from overwriting other items. */
547 static void ClipToShadowInteriorAndLongest(lw
, gc_p
, x
)
555 rect
.y
= lw
->list
.internal_height
;
556 rect
.height
= lw
->core
.height
- lw
->list
.internal_height
* 2;
557 rect
.width
= lw
->core
.width
- lw
->list
.internal_width
- x
;
558 if ( rect
.width
> lw
->list
.longest
)
559 rect
.width
= lw
->list
.longest
;
561 XSetClipRectangles( XtDisplay((Widget
)lw
),*gc_p
,0,0,&rect
,1,YXBanded
);
567 * paints the name of the item in the appropriate location.
568 * w - the list widget.
569 * item - the item to draw.
571 * NOTE: no action taken on an unrealized widget. */
574 PaintItemName(w
, item
)
581 ListWidget lw
= (ListWidget
) w
;
582 XFontSetExtents
*ext
= XExtentsOfFontSet(lw
->list
.fontset
);
584 if (!XtIsRealized(w
)) return; /* Just in case... */
586 if (lw
->list
.vertical_cols
) {
587 x
= lw
->list
.col_width
* (item
/ lw
->list
.nrows
)
588 + lw
->list
.internal_width
;
589 y
= lw
->list
.row_height
* (item
% lw
->list
.nrows
)
590 + lw
->list
.internal_height
;
593 x
= lw
->list
.col_width
* (item
% lw
->list
.ncols
)
594 + lw
->list
.internal_width
;
595 y
= lw
->list
.row_height
* (item
/ lw
->list
.ncols
)
596 + lw
->list
.internal_height
;
599 if ( lw
->simple
.international
== True
)
600 str_y
= y
+ abs(ext
->max_ink_extent
.y
);
602 str_y
= y
+ lw
->list
.font
->max_bounds
.ascent
;
604 if (item
== lw
->list
.is_highlighted
) {
605 if (item
== lw
->list
.highlight
) {
607 HighlightBackground(w
, x
, y
, lw
->list
.normgc
);
610 if (XtIsSensitive(w
))
611 gc
= lw
->list
.normgc
;
613 gc
= lw
->list
.graygc
;
614 HighlightBackground(w
, x
, y
, lw
->list
.revgc
);
615 lw
->list
.is_highlighted
= NO_HIGHLIGHT
;
619 if (item
== lw
->list
.highlight
) {
621 HighlightBackground(w
, x
, y
, lw
->list
.normgc
);
622 lw
->list
.is_highlighted
= item
;
625 if (XtIsSensitive(w
))
626 gc
= lw
->list
.normgc
;
628 gc
= lw
->list
.graygc
;
632 /* List's overall width contains the same number of inter-column
633 column_space's as columns. There should thus be a half
634 column_width margin on each side of each column.
635 The row case is symmetric. */
637 x
+= lw
->list
.column_space
/ 2;
638 str_y
+= lw
->list
.row_space
/ 2;
640 str
= lw
->list
.list
[item
]; /* draw it */
642 ClipToShadowInteriorAndLongest( lw
, &gc
, x
);
644 if ( lw
->simple
.international
== True
)
645 XmbDrawString( XtDisplay( w
), XtWindow( w
), lw
->list
.fontset
,
646 gc
, x
, str_y
, str
, strlen( str
) );
648 XDrawString( XtDisplay( w
), XtWindow( w
),
649 gc
, x
, str_y
, str
, strlen( str
) );
651 XSetClipMask( XtDisplay( w
), gc
, None
);
657 * Repaints the widget window on expose events.
658 * w - the list widget.
659 * event - the expose event for this repaint.
660 * junk - not used, unless three-d patch enabled. */
664 Redisplay(w
, event
, junk
)
669 int item
; /* an item to work with. */
670 int ul_item
, lr_item
; /* corners of items we need to paint. */
671 ListWidget lw
= (ListWidget
) w
;
673 if (event
== NULL
) { /* repaint all. */
675 lr_item
= lw
->list
.nrows
* lw
->list
.ncols
- 1;
676 XClearWindow(XtDisplay(w
), XtWindow(w
));
679 FindCornerItems(w
, event
, &ul_item
, &lr_item
);
681 for (item
= ul_item
; (item
<= lr_item
&& item
< lw
->list
.nitems
) ; item
++)
682 if (ItemInRectangle(w
, ul_item
, lr_item
, item
))
683 PaintItemName(w
, item
);
689 * This tells the parent what size we would like to be
690 * given certain constraints.
692 * intended - what the parent intends to do with us.
693 * requested - what we want to happen. */
695 static XtGeometryResult
696 PreferredGeom(w
, intended
, requested
)
698 XtWidgetGeometry
*intended
, *requested
;
700 Dimension new_width
, new_height
;
701 Boolean change
, width_req
, height_req
;
703 width_req
= intended
->request_mode
& CWWidth
;
704 height_req
= intended
->request_mode
& CWHeight
;
707 new_width
= intended
->width
;
709 new_width
= w
->core
.width
;
712 new_height
= intended
->height
;
714 new_height
= w
->core
.height
;
716 requested
->request_mode
= 0;
719 * We only care about our height and width.
722 if ( !width_req
&& !height_req
)
723 return(XtGeometryYes
);
725 change
= Layout(w
, !width_req
, !height_req
, &new_width
, &new_height
);
727 requested
->request_mode
|= CWWidth
;
728 requested
->width
= new_width
;
729 requested
->request_mode
|= CWHeight
;
730 requested
->height
= new_height
;
733 return(XtGeometryAlmost
);
734 return(XtGeometryYes
);
740 * resizes the widget, by changing the number of rows and columns. */
746 Dimension width
, height
;
748 width
= w
->core
.width
;
749 height
= w
->core
.height
;
751 if (Layout(w
, FALSE
, FALSE
, &width
, &height
))
752 XtAppWarning(XtWidgetToApplicationContext(w
),
753 "List Widget: Size changed when it shouldn't have when resising.");
759 * lays out the item in the list.
761 * xfree, yfree - TRUE if we are free to resize the widget in
763 * width, height- the is the current width and height that we are going
764 * we are going to layout the list widget to,
765 * depending on xfree and yfree of course.
767 * RETURNS: TRUE if width or height have been changed. */
770 Layout(w
, xfree
, yfree
, width
, height
)
772 Boolean xfree
, yfree
;
773 Dimension
*width
, *height
;
775 ListWidget lw
= (ListWidget
) w
;
776 Boolean change
= FALSE
;
779 * If force columns is set then always use number of columns specified
783 if (lw
->list
.force_cols
) {
784 lw
->list
.ncols
= lw
->list
.default_cols
;
785 if (lw
->list
.ncols
<= 0) lw
->list
.ncols
= 1;
786 /* 12/3 = 4 and 10/3 = 4, but 9/3 = 3 */
787 lw
->list
.nrows
= ( ( lw
->list
.nitems
- 1) / lw
->list
.ncols
) + 1 ;
788 if (xfree
) { /* If allowed resize width. */
790 /* this counts the same number
791 of inter-column column_space 's as columns. There should thus be a
792 half column_space margin on each side of each column...*/
794 *width
= lw
->list
.ncols
* lw
->list
.col_width
795 + 2 * lw
->list
.internal_width
;
798 if (yfree
) { /* If allowed resize height. */
799 *height
= (lw
->list
.nrows
* lw
->list
.row_height
)
800 + 2 * lw
->list
.internal_height
;
807 * If both width and height are free to change the use default_cols
808 * to determine the number columns and set new width and height to
809 * just fit the window.
812 if (xfree
&& yfree
) {
813 lw
->list
.ncols
= lw
->list
.default_cols
;
814 if (lw
->list
.ncols
<= 0) lw
->list
.ncols
= 1;
815 lw
->list
.nrows
= ( ( lw
->list
.nitems
- 1) / lw
->list
.ncols
) + 1 ;
816 *width
= lw
->list
.ncols
* lw
->list
.col_width
817 + 2 * lw
->list
.internal_width
;
818 *height
= (lw
->list
.nrows
* lw
->list
.row_height
)
819 + 2 * lw
->list
.internal_height
;
823 * If the width is fixed then use it to determine the number of columns.
824 * If the height is free to move (width still fixed) then resize the height
825 * of the widget to fit the current list exactly.
828 lw
->list
.ncols
= ( (int)(*width
- 2 * lw
->list
.internal_width
)
829 / (int)lw
->list
.col_width
);
830 if (lw
->list
.ncols
<= 0) lw
->list
.ncols
= 1;
831 lw
->list
.nrows
= ( ( lw
->list
.nitems
- 1) / lw
->list
.ncols
) + 1 ;
833 *height
= (lw
->list
.nrows
* lw
->list
.row_height
)
834 + 2 * lw
->list
.internal_height
;
839 * The last case is xfree and !yfree we use the height to determine
840 * the number of rows and then set the width to just fit the resulting
843 else if (!yfree
) { /* xfree must be TRUE. */
844 lw
->list
.nrows
= (int)(*height
- 2 * lw
->list
.internal_height
)
845 / (int)lw
->list
.row_height
;
846 if (lw
->list
.nrows
<= 0) lw
->list
.nrows
= 1;
847 lw
->list
.ncols
= (( lw
->list
.nitems
- 1 ) / lw
->list
.nrows
) + 1;
848 *width
= lw
->list
.ncols
* lw
->list
.col_width
849 + 2 * lw
->list
.internal_width
;
858 * Notifies the user that a button has been pressed, and
859 * calls the callback; if the XtNpasteBuffer resource is true
860 * then the name of the item is also put in CUT_BUFFER0. */
864 Notify(w
, event
, params
, num_params
)
868 Cardinal
*num_params
;
870 ListWidget lw
= ( ListWidget
) w
;
872 XawListReturnStruct ret_value
;
875 * Find item and if out of range then unhighlight and return.
877 * If the current item is unhighlighted then the user has aborted the
878 * notify, so unhighlight and return.
881 if ( ((CvtToItem(w
, event
->xbutton
.x
, event
->xbutton
.y
, &item
))
882 == OUT_OF_RANGE
) || (lw
->list
.highlight
!= item
) ) {
883 XawListUnhighlight(w
);
887 item_len
= strlen(lw
->list
.list
[item
]);
889 if ( lw
->list
.paste
) /* if XtNpasteBuffer set then paste it. */
890 XStoreBytes(XtDisplay(w
), lw
->list
.list
[item
], item_len
);
893 * Call Callback function.
896 ret_value
.string
= lw
->list
.list
[item
];
897 ret_value
.list_index
= item
;
899 XtCallCallbacks( w
, XtNcallback
, (XtPointer
) &ret_value
);
905 * unhighlights the current element. */
909 Unset(w
, event
, params
, num_params
)
913 Cardinal
*num_params
;
915 XawListUnhighlight(w
);
921 * Highlights the current element. */
925 Set(w
, event
, params
, num_params
)
929 Cardinal
*num_params
;
932 ListWidget lw
= (ListWidget
) w
;
934 if ( (CvtToItem(w
, event
->xbutton
.x
, event
->xbutton
.y
, &item
))
936 XawListUnhighlight(w
); /* Unhighlight current item. */
937 else if ( lw
->list
.is_highlighted
!= item
) /* If this item is not */
938 XawListHighlight(w
, item
); /* highlighted then do it. */
942 * Set specified arguments into widget
946 SetValues(current
, request
, new, args
, num_args
)
947 Widget current
, request
, new;
951 ListWidget cl
= (ListWidget
) current
;
952 ListWidget rl
= (ListWidget
) request
;
953 ListWidget nl
= (ListWidget
) new;
954 Boolean redraw
= FALSE
;
955 XFontSetExtents
*ext
= XExtentsOfFontSet(nl
->list
.fontset
);
957 /* If the request height/width is different, lock it. Unless its 0. If */
958 /* neither new nor 0, leave it as it was. Not in R5. */
959 if ( nl
->core
.width
!= cl
->core
.width
)
960 nl
->list
.freedoms
|= WidthLock
;
961 if ( nl
->core
.width
== 0 )
962 nl
->list
.freedoms
&= ~WidthLock
;
964 if ( nl
->core
.height
!= cl
->core
.height
)
965 nl
->list
.freedoms
|= HeightLock
;
966 if ( nl
->core
.height
== 0 )
967 nl
->list
.freedoms
&= ~HeightLock
;
969 if ( nl
->list
.longest
!= cl
->list
.longest
)
970 nl
->list
.freedoms
|= LongestLock
;
971 if ( nl
->list
.longest
== 0 )
972 nl
->list
.freedoms
&= ~LongestLock
;
974 /* _DONT_ check for fontset here - it's not in GC.*/
976 if ( (cl
->list
.foreground
!= nl
->list
.foreground
) ||
977 (cl
->core
.background_pixel
!= nl
->core
.background_pixel
) ||
978 (cl
->list
.font
!= nl
->list
.font
) ) {
980 XGetGCValues(XtDisplay(current
), cl
->list
.graygc
, GCTile
, &values
);
981 XmuReleaseStippledPixmap(XtScreen(current
), values
.tile
);
982 XtReleaseGC(current
, cl
->list
.graygc
);
983 XtReleaseGC(current
, cl
->list
.revgc
);
984 XtReleaseGC(current
, cl
->list
.normgc
);
989 if ( ( cl
->list
.font
!= nl
->list
.font
) &&
990 ( cl
->simple
.international
== False
) )
991 nl
->list
.row_height
= nl
->list
.font
->max_bounds
.ascent
992 + nl
->list
.font
->max_bounds
.descent
993 + nl
->list
.row_space
;
995 else if ( ( cl
->list
.fontset
!= nl
->list
.fontset
) &&
996 ( cl
->simple
.international
== True
) )
997 nl
->list
.row_height
= ext
->max_ink_extent
.height
+ nl
->list
.row_space
;
999 /* ...If the above two font(set) change checkers above both failed, check
1000 if row_space was altered. If one of the above passed, row_height will
1001 already have been re-calculated. */
1003 else if ( cl
->list
.row_space
!= nl
->list
.row_space
) {
1005 if (cl
->simple
.international
== True
)
1006 nl
->list
.row_height
= ext
->max_ink_extent
.height
+ nl
->list
.row_space
;
1008 nl
->list
.row_height
= nl
->list
.font
->max_bounds
.ascent
1009 + nl
->list
.font
->max_bounds
.descent
1010 + nl
->list
.row_space
;
1013 if ((cl
->core
.width
!= nl
->core
.width
) ||
1014 (cl
->core
.height
!= nl
->core
.height
) ||
1015 (cl
->list
.internal_width
!= nl
->list
.internal_width
) ||
1016 (cl
->list
.internal_height
!= nl
->list
.internal_height
) ||
1017 (cl
->list
.column_space
!= nl
->list
.column_space
) ||
1018 (cl
->list
.row_space
!= nl
->list
.row_space
) ||
1019 (cl
->list
.default_cols
!= nl
->list
.default_cols
) ||
1020 ( (cl
->list
.force_cols
!= nl
->list
.force_cols
) &&
1021 (rl
->list
.force_cols
!= nl
->list
.ncols
) ) ||
1022 (cl
->list
.vertical_cols
!= nl
->list
.vertical_cols
) ||
1023 (cl
->list
.longest
!= nl
->list
.longest
) ||
1024 (cl
->list
.nitems
!= nl
->list
.nitems
) ||
1025 (cl
->list
.font
!= nl
->list
.font
) ||
1026 /* Equiv. fontsets might have different values, but the same fonts, so the
1027 next comparison is sloppy but not dangerous. */
1028 (cl
->list
.fontset
!= nl
->list
.fontset
) ||
1029 (cl
->list
.list
!= nl
->list
.list
) ) {
1031 CalculatedValues( new );
1032 Layout( new, WidthFree( nl
), HeightFree( nl
),
1033 &nl
->core
.width
, &nl
->core
.height
);
1037 if (cl
->list
.list
!= nl
->list
.list
)
1038 nl
->list
.is_highlighted
= nl
->list
.highlight
= NO_HIGHLIGHT
;
1040 if ((cl
->core
.sensitive
!= nl
->core
.sensitive
) ||
1041 (cl
->core
.ancestor_sensitive
!= nl
->core
.ancestor_sensitive
)) {
1042 nl
->list
.highlight
= NO_HIGHLIGHT
;
1046 if (!XtIsRealized(current
))
1052 static void Destroy(w
)
1055 ListWidget lw
= (ListWidget
) w
;
1058 XGetGCValues(XtDisplay(w
), lw
->list
.graygc
, GCTile
, &values
);
1059 XmuReleaseStippledPixmap(XtScreen(w
), values
.tile
);
1060 XtReleaseGC(w
, lw
->list
.graygc
);
1061 XtReleaseGC(w
, lw
->list
.revgc
);
1062 XtReleaseGC(w
, lw
->list
.normgc
);
1065 /* Exported Functions */
1067 /* Function Name: XawListChange.
1068 * Description: Changes the list being used and shown.
1069 * Arguments: w - the list widget.
1070 * list - the new list.
1071 * nitems - the number of items in the list.
1072 * longest - the length (in Pixels) of the longest element
1074 * resize - if TRUE the the list widget will
1075 * try to resize itself.
1077 * NOTE: If nitems of longest are <= 0 then they will be calculated.
1078 * If nitems is <= 0 then the list needs to be NULL terminated.
1082 #if NeedFunctionPrototypes
1083 XawListChange(Widget w
, char ** list
, int nitems
, int longest
,
1084 #if NeedWidePrototypes
1090 XawListChange(w
, list
, nitems
, longest
, resize_it
)
1093 int nitems
, longest
;
1097 ListWidget lw
= (ListWidget
) w
;
1098 Dimension new_width
= w
->core
.width
;
1099 Dimension new_height
= w
->core
.height
;
1101 lw
->list
.list
= list
;
1103 if ( nitems
<= 0 ) nitems
= 0;
1104 lw
->list
.nitems
= nitems
;
1105 if ( longest
<= 0 ) longest
= 0;
1107 /* If the user passes 0 meaning "calculate it", it must be free */
1109 lw
->list
.freedoms
|= LongestLock
;
1110 else /* the user's word is god. */
1111 lw
->list
.freedoms
&= ~LongestLock
;
1114 lw
->list
.freedoms
&= ~WidthLock
& ~HeightLock
;
1115 /* else - still resize if its not locked */
1117 lw
->list
.longest
= longest
;
1119 CalculatedValues( w
);
1121 if( Layout( w
, WidthFree( w
), HeightFree( w
),
1122 &new_width
, &new_height
) )
1123 ChangeSize( w
, new_width
, new_height
);
1125 lw
->list
.is_highlighted
= lw
->list
.highlight
= NO_HIGHLIGHT
;
1126 if ( XtIsRealized( w
) )
1127 Redisplay( w
, (XEvent
*)NULL
, (Region
)NULL
);
1130 /* Function Name: XawListUnhighlight
1131 * Description: unlights the current highlighted element.
1132 * Arguments: w - the widget.
1137 #if NeedFunctionPrototypes
1138 XawListUnhighlight(Widget w
)
1140 XawListUnhighlight(w
)
1144 ListWidget lw
= ( ListWidget
) w
;
1146 lw
->list
.highlight
= NO_HIGHLIGHT
;
1147 if (lw
->list
.is_highlighted
!= NO_HIGHLIGHT
)
1148 PaintItemName(w
, lw
->list
.is_highlighted
); /* unhighlight this one. */
1151 /* Function Name: XawListHighlight
1152 * Description: Highlights the given item.
1153 * Arguments: w - the list widget.
1154 * item - the item to hightlight.
1159 #if NeedFunctionPrototypes
1160 XawListHighlight(Widget w
, int item
)
1162 XawListHighlight(w
, item
)
1167 ListWidget lw
= ( ListWidget
) w
;
1169 if (XtIsSensitive(w
)) {
1170 lw
->list
.highlight
= item
;
1171 if (lw
->list
.is_highlighted
!= NO_HIGHLIGHT
)
1172 PaintItemName(w
, lw
->list
.is_highlighted
); /* Unhighlight. */
1173 PaintItemName(w
, item
); /* HIGHLIGHT this one. */
1177 /* Function Name: XawListShowCurrent
1178 * Description: returns the currently highlighted object.
1179 * Arguments: w - the list widget.
1180 * Returns: the info about the currently highlighted object.
1183 XawListReturnStruct
*
1184 #if NeedFunctionPrototypes
1185 XawListShowCurrent(Widget w
)
1187 XawListShowCurrent(w
)
1191 ListWidget lw
= ( ListWidget
) w
;
1192 XawListReturnStruct
* ret_val
;
1194 ret_val
= (XawListReturnStruct
*)
1195 XtMalloc (sizeof (XawListReturnStruct
));/* SPARE MALLOC OK */
1197 ret_val
->list_index
= lw
->list
.highlight
;
1198 if (ret_val
->list_index
== XAW_LIST_NONE
)
1199 ret_val
->string
= "";
1201 ret_val
->string
= lw
->list
.list
[ ret_val
->list_index
];