swi-prolog: update to 9.2.9
[oi-userland.git] / components / x11 / libXaw5 / src / List.c
blobcbaa33a997d8ccc151c7d4d6634a6ec1462b9882
1 /* $XConsortium: List.c,v 1.39 94/04/17 20:12:15 kaleb Exp $ */
3 /*
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.
34 * Created: 8/13/88
35 * By: Chris D. Peterson
36 * MIT X Consortium
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <ctype.h>
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. */
54 #define HeightLock 1
55 #define WidthLock 2
56 #define LongestLock 4
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 )
62 /*
63 * Default Translation table.
66 static char defaultTranslations[] =
67 "<Btn1Down>: Set()\n\
68 <Btn1Up>: Notify()";
70 /****************************************************************
72 * Full class record constant
74 ****************************************************************/
76 /* Private Data */
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[] = {
126 {"Notify", Notify},
127 {"Set", Set},
128 {"Unset", Unset},
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,
153 /* resize */ Resize,
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 */
171 /* not used */ 0
175 WidgetClass listWidgetClass = (WidgetClass)&listClassRec;
177 /****************************************************************
179 * Private Procedures
181 ****************************************************************/
183 static void GetGCs(w)
184 Widget w;
186 XGCValues values;
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 );
195 else
196 lw->list.normgc = XtGetGC( w, (unsigned) GCForeground | GCFont,
197 &values);
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 );
204 else
205 lw->list.revgc = XtGetGC( w, (unsigned) GCForeground | GCFont,
206 &values);
208 values.tile = XmuCreateStippledPixmap(XtScreen(w),
209 lw->list.foreground,
210 lw->core.background_pixel,
211 lw->core.depth);
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 );
217 else
218 lw->list.graygc = XtGetGC( w, (unsigned) GCFont | GCTile | GCFillStyle,
219 &values);
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 )
234 Widget w;
236 int i, len;
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);
244 lw->list.nitems = 1;
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]));
262 else
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
281 static void
282 ResetList( w, changex, changey )
283 Widget w;
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.
298 * Returns: none.
301 static void
302 ChangeSize(w, width, height)
303 Widget w;
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) ) {
313 case XtGeometryYes:
314 break;
315 case XtGeometryNo:
316 break;
317 case XtGeometryAlmost:
318 Layout(w, (request.height != reply.height),
319 (request.width != reply.width),
320 &(reply.width), &(reply.height));
321 request = reply;
322 switch (XtMakeGeometryRequest(w, &request, &reply) ) {
323 case XtGeometryYes:
324 case XtGeometryNo:
325 break;
326 case XtGeometryAlmost:
327 request = reply;
328 Layout(w, FALSE, FALSE, &(request.width), &(request.height));
329 request.request_mode = CWWidth | CWHeight;
330 XtMakeGeometryRequest(w, &request, &reply);
331 break;
332 default:
333 XtAppWarning(XtWidgetToApplicationContext(w),
334 "List Widget: Unknown geometry return.");
335 break;
337 break;
338 default:
339 XtAppWarning(XtWidgetToApplicationContext(w),
340 "List Widget: Unknown geometry return.");
341 break;
345 /* Function Name: Initialize
346 * Description: Function that initilizes the widget instance.
347 * Arguments: junk - NOT USED.
348 * new - the new widget.
349 * Returns: none
352 /* ARGSUSED */
353 static void
354 Initialize(junk, new, args, num_args)
355 Widget junk, new;
356 ArgList args;
357 Cardinal *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;
370 GetGCs(new);
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;
378 else
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;
387 } /* Initialize */
389 /* Function Name: CvtToItem
390 * Description: Converts Xcoord to item number of item containing that
391 * point.
392 * Arguments: w - the list widget.
393 * xloc, yloc - x location, and y location.
394 * Returns: the item number.
397 static int
398 CvtToItem(w, xloc, yloc, item)
399 Widget w;
400 int xloc, yloc;
401 int *item;
403 int one, another;
404 ListWidget lw = (ListWidget) w;
405 int ret_val = OKAY;
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;
418 else {
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);
434 return(ret_val);
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 **.
442 * Returns: none.
445 static void
446 FindCornerItems(w, event, ul_ret, lr_ret)
447 Widget w;
448 XEvent * event;
449 int *ul_ret, *lr_ret;
451 int xloc, yloc;
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.
469 static Boolean
470 ItemInRectangle(w, ul, lr, item)
471 Widget w;
472 int ul, lr, item;
474 ListWidget lw = (ListWidget) w;
475 int mod_item;
476 int things;
478 if (item < ul || item > lr)
479 return(FALSE);
480 if (lw->list.vertical_cols)
481 things = lw->list.nrows;
482 else
483 things = lw->list.ncols;
485 mod_item = item % things;
486 if ( (mod_item >= ul % things) && (mod_item <= lr % things ) )
487 return(TRUE);
488 return(FALSE);
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 */
501 static void
502 HighlightBackground( w, x, y, gc )
503 Widget w;
504 int x, y;
505 GC 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,
534 width, height );
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)
548 ListWidget lw;
549 GC* gc_p;
550 Dimension x;
552 XRectangle rect;
554 rect.x = 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 );
565 /* PaintItemName()
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. */
573 static void
574 PaintItemName(w, item)
575 Widget w;
576 int item;
578 char * str;
579 GC gc;
580 int x, y, str_y;
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;
592 else {
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);
601 else
602 str_y = y + lw->list.font->max_bounds.ascent;
604 if (item == lw->list.is_highlighted) {
605 if (item == lw->list.highlight) {
606 gc = lw->list.revgc;
607 HighlightBackground(w, x, y, lw->list.normgc);
609 else {
610 if (XtIsSensitive(w))
611 gc = lw->list.normgc;
612 else
613 gc = lw->list.graygc;
614 HighlightBackground(w, x, y, lw->list.revgc);
615 lw->list.is_highlighted = NO_HIGHLIGHT;
618 else {
619 if (item == lw->list.highlight) {
620 gc = lw->list.revgc;
621 HighlightBackground(w, x, y, lw->list.normgc);
622 lw->list.is_highlighted = item;
624 else {
625 if (XtIsSensitive(w))
626 gc = lw->list.normgc;
627 else
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 ) );
647 else
648 XDrawString( XtDisplay( w ), XtWindow( w ),
649 gc, x, str_y, str, strlen( str ) );
651 XSetClipMask( XtDisplay( w ), gc, None );
655 /* Redisplay()
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. */
662 /* ARGSUSED */
663 static void
664 Redisplay(w, event, junk)
665 Widget w;
666 XEvent *event;
667 Region 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. */
674 ul_item = 0;
675 lr_item = lw->list.nrows * lw->list.ncols - 1;
676 XClearWindow(XtDisplay(w), XtWindow(w));
678 else
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);
687 /* PreferredGeom()
689 * This tells the parent what size we would like to be
690 * given certain constraints.
691 * w - the widget.
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)
697 Widget w;
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;
706 if (width_req)
707 new_width = intended->width;
708 else
709 new_width = w->core.width;
711 if (height_req)
712 new_height = intended->height;
713 else
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;
732 if (change)
733 return(XtGeometryAlmost);
734 return(XtGeometryYes);
738 /* Resize()
740 * resizes the widget, by changing the number of rows and columns. */
742 static void
743 Resize(w)
744 Widget w;
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.");
757 /* Layout()
759 * lays out the item in the list.
760 * w - the widget.
761 * xfree, yfree - TRUE if we are free to resize the widget in
762 * this direction.
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. */
769 static Boolean
770 Layout(w, xfree, yfree, width, height)
771 Widget w;
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
780 * by default_cols.
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;
796 change = TRUE;
798 if (yfree) { /* If allowed resize height. */
799 *height = (lw->list.nrows * lw->list.row_height)
800 + 2 * lw->list.internal_height;
801 change = TRUE;
803 return(change);
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;
820 change = TRUE;
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.
827 else if (!xfree) {
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 ;
832 if ( yfree ) {
833 *height = (lw->list.nrows * lw->list.row_height)
834 + 2 * lw->list.internal_height;
835 change = TRUE;
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
841 * number of columns.
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;
850 change = TRUE;
852 return(change);
856 /* Notify() - ACTION
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. */
862 /* ARGSUSED */
863 static void
864 Notify(w, event, params, num_params)
865 Widget w;
866 XEvent * event;
867 String * params;
868 Cardinal *num_params;
870 ListWidget lw = ( ListWidget ) w;
871 int item, item_len;
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);
884 return;
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);
903 /* Unset() - ACTION
905 * unhighlights the current element. */
907 /* ARGSUSED */
908 static void
909 Unset(w, event, params, num_params)
910 Widget w;
911 XEvent * event;
912 String * params;
913 Cardinal *num_params;
915 XawListUnhighlight(w);
919 /* Set() - ACTION
921 * Highlights the current element. */
923 /* ARGSUSED */
924 static void
925 Set(w, event, params, num_params)
926 Widget w;
927 XEvent * event;
928 String * params;
929 Cardinal *num_params;
931 int item;
932 ListWidget lw = (ListWidget) w;
934 if ( (CvtToItem(w, event->xbutton.x, event->xbutton.y, &item))
935 == OUT_OF_RANGE)
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
945 static Boolean
946 SetValues(current, request, new, args, num_args)
947 Widget current, request, new;
948 ArgList args;
949 Cardinal *num_args;
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) ) {
979 XGCValues values;
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);
985 GetGCs(new);
986 redraw = TRUE;
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;
1007 else
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 );
1034 redraw = TRUE;
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;
1043 redraw = TRUE;
1046 if (!XtIsRealized(current))
1047 return(FALSE);
1049 return(redraw);
1052 static void Destroy(w)
1053 Widget w;
1055 ListWidget lw = (ListWidget) w;
1056 XGCValues values;
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
1073 * in the list.
1074 * resize - if TRUE the the list widget will
1075 * try to resize itself.
1076 * Returns: none.
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.
1081 void
1082 #if NeedFunctionPrototypes
1083 XawListChange(Widget w, char ** list, int nitems, int longest,
1084 #if NeedWidePrototypes
1085 int resize_it)
1086 #else
1087 Boolean resize_it)
1088 #endif
1089 #else
1090 XawListChange(w, list, nitems, longest, resize_it)
1091 Widget w;
1092 char ** list;
1093 int nitems, longest;
1094 Boolean resize_it;
1095 #endif
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 */
1108 if ( longest != 0 )
1109 lw->list.freedoms |= LongestLock;
1110 else /* the user's word is god. */
1111 lw->list.freedoms &= ~LongestLock;
1113 if ( resize_it )
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.
1133 * Returns: none.
1136 void
1137 #if NeedFunctionPrototypes
1138 XawListUnhighlight(Widget w)
1139 #else
1140 XawListUnhighlight(w)
1141 Widget w;
1142 #endif
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.
1155 * Returns: none.
1158 void
1159 #if NeedFunctionPrototypes
1160 XawListHighlight(Widget w, int item)
1161 #else
1162 XawListHighlight(w, item)
1163 Widget w;
1164 int item;
1165 #endif
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)
1186 #else
1187 XawListShowCurrent(w)
1188 Widget w;
1189 #endif
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 = "";
1200 else
1201 ret_val->string = lw->list.list[ ret_val->list_index ];
1203 return(ret_val);