749N/A/* $XConsortium: List.c,v 1.39 94/04/17 20:12:15 kaleb Exp $ */
749N/A
749N/A/*
749N/ACopyright (c) 1989, 1994 X Consortium
749N/A
749N/APermission is hereby granted, free of charge, to any person obtaining a copy
749N/Aof this software and associated documentation files (the "Software"), to deal
749N/Ain the Software without restriction, including without limitation the rights
749N/Ato use, copy, modify, merge, publish, distribute, sublicense, and/or sell
749N/Acopies of the Software, and to permit persons to whom the Software is
749N/Afurnished to do so, subject to the following conditions:
749N/A
749N/AThe above copyright notice and this permission notice shall be included in
749N/Aall copies or substantial portions of the Software.
749N/A
749N/ATHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
749N/AIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
749N/AFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
749N/AX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
749N/AAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
749N/ACONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
749N/A
749N/AExcept as contained in this notice, the name of the X Consortium shall not be
749N/Aused in advertising or otherwise to promote the sale, use or other dealings
749N/Ain this Software without prior written authorization from the X Consortium.
749N/A*/
749N/A
749N/A/*
749N/A * List.c - List widget
749N/A *
749N/A * This is a List widget. It allows the user to select an item in a list and
749N/A * notifies the application through a callback function.
749N/A *
749N/A * Created: 8/13/88
749N/A * By: Chris D. Peterson
749N/A * MIT X Consortium
749N/A */
749N/A
749N/A#include <stdio.h>
749N/A#include <stdlib.h>
749N/A#include <ctype.h>
749N/A
749N/A#include <X11/IntrinsicP.h>
749N/A#include <X11/StringDefs.h>
749N/A
749N/A#include <X11/Xmu/Drawing.h>
749N/A
749N/A#include <X11/Xaw/XawInit.h>
749N/A#include <X11/Xaw/ListP.h>
749N/A
749N/A/* These added so widget knows whether its height, width are user selected.
749N/AI also added the freedoms member of the list widget part. */
749N/A
749N/A#define HeightLock 1
749N/A#define WidthLock 2
749N/A#define LongestLock 4
749N/A
749N/A#define HeightFree( w ) !(((ListWidget)(w))->list.freedoms & HeightLock )
749N/A#define WidthFree( w ) !(((ListWidget)(w))->list.freedoms & WidthLock )
749N/A#define LongestFree( w ) !(((ListWidget)(w))->list.freedoms & LongestLock )
749N/A
749N/A/*
749N/A * Default Translation table.
749N/A */
749N/A
749N/Astatic char defaultTranslations[] =
749N/A "<Btn1Down>: Set()\n\
749N/A <Btn1Up>: Notify()";
749N/A
749N/A/****************************************************************
749N/A *
749N/A * Full class record constant
749N/A *
749N/A ****************************************************************/
749N/A
749N/A/* Private Data */
749N/A
749N/A#define offset(field) XtOffset(ListWidget, field)
749N/A
749N/Astatic XtResource resources[] = {
749N/A {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
749N/A offset(list.foreground), XtRString, XtDefaultForeground},
749N/A {XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor),
749N/A offset(simple.cursor), XtRString, "left_ptr"},
749N/A {XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
749N/A offset(list.font),XtRString, XtDefaultFont},
749N/A {XtNfontSet, XtCFontSet, XtRFontSet, sizeof(XFontSet ),
749N/A offset(list.fontset),XtRString, XtDefaultFontSet},
749N/A {XtNlist, XtCList, XtRPointer, sizeof(char **),
749N/A offset(list.list), XtRString, NULL},
749N/A {XtNdefaultColumns, XtCColumns, XtRInt, sizeof(int),
749N/A offset(list.default_cols), XtRImmediate, (XtPointer)2},
749N/A {XtNlongest, XtCLongest, XtRInt, sizeof(int),
749N/A offset(list.longest), XtRImmediate, (XtPointer)0},
749N/A {XtNnumberStrings, XtCNumberStrings, XtRInt, sizeof(int),
749N/A offset(list.nitems), XtRImmediate, (XtPointer)0},
749N/A {XtNpasteBuffer, XtCBoolean, XtRBoolean, sizeof(Boolean),
749N/A offset(list.paste), XtRImmediate, (XtPointer) False},
749N/A {XtNforceColumns, XtCColumns, XtRBoolean, sizeof(Boolean),
749N/A offset(list.force_cols), XtRImmediate, (XtPointer) False},
749N/A {XtNverticalList, XtCBoolean, XtRBoolean, sizeof(Boolean),
749N/A offset(list.vertical_cols), XtRImmediate, (XtPointer) False},
749N/A {XtNinternalWidth, XtCWidth, XtRDimension, sizeof(Dimension),
749N/A offset(list.internal_width), XtRImmediate, (XtPointer)2},
749N/A {XtNinternalHeight, XtCHeight, XtRDimension, sizeof(Dimension),
749N/A offset(list.internal_height), XtRImmediate, (XtPointer)2},
749N/A {XtNcolumnSpacing, XtCSpacing, XtRDimension, sizeof(Dimension),
749N/A offset(list.column_space), XtRImmediate, (XtPointer)6},
749N/A {XtNrowSpacing, XtCSpacing, XtRDimension, sizeof(Dimension),
749N/A offset(list.row_space), XtRImmediate, (XtPointer)2},
749N/A {XtNcallback, XtCCallback, XtRCallback, sizeof(XtPointer),
749N/A offset(list.callback), XtRCallback, NULL},
749N/A};
749N/A
749N/Astatic void Initialize();
749N/Astatic void ChangeSize();
749N/Astatic void Resize();
749N/Astatic void Redisplay();
749N/Astatic void Destroy();
749N/Astatic Boolean Layout();
749N/Astatic XtGeometryResult PreferredGeom();
749N/Astatic Boolean SetValues();
749N/Astatic void Notify(), Set(), Unset();
749N/A
749N/Astatic XtActionsRec actions[] = {
749N/A {"Notify", Notify},
749N/A {"Set", Set},
749N/A {"Unset", Unset},
749N/A};
749N/A
749N/AListClassRec listClassRec = {
749N/A {
749N/A/* core_class fields */
749N/A /* superclass */ (WidgetClass) &simpleClassRec,
749N/A /* class_name */ "List",
749N/A /* widget_size */ sizeof(ListRec),
749N/A /* class_initialize */ XawInitializeWidgetSet,
749N/A /* class_part_initialize */ NULL,
749N/A /* class_inited */ FALSE,
749N/A /* initialize */ Initialize,
749N/A /* initialize_hook */ NULL,
749N/A /* realize */ XtInheritRealize,
749N/A /* actions */ actions,
749N/A /* num_actions */ XtNumber(actions),
749N/A /* resources */ resources,
749N/A /* num_resources */ XtNumber(resources),
749N/A /* xrm_class */ NULLQUARK,
749N/A /* compress_motion */ TRUE,
749N/A /* compress_exposure */ FALSE,
749N/A /* compress_enterleave */ TRUE,
749N/A /* visible_interest */ FALSE,
749N/A /* destroy */ Destroy,
749N/A /* resize */ Resize,
749N/A /* expose */ Redisplay,
749N/A /* set_values */ SetValues,
749N/A /* set_values_hook */ NULL,
749N/A /* set_values_almost */ XtInheritSetValuesAlmost,
749N/A /* get_values_hook */ NULL,
749N/A /* accept_focus */ NULL,
749N/A /* version */ XtVersion,
749N/A /* callback_private */ NULL,
749N/A /* tm_table */ defaultTranslations,
749N/A /* query_geometry */ PreferredGeom,
749N/A },
749N/A/* Simple class fields initialization */
749N/A {
749N/A /* change_sensitive */ XtInheritChangeSensitive
749N/A },
749N/A/* List class fields initialization */
749N/A {
749N/A /* not used */ 0
749N/A },
749N/A};
749N/A
749N/AWidgetClass listWidgetClass = (WidgetClass)&listClassRec;
749N/A
749N/A/****************************************************************
749N/A *
749N/A * Private Procedures
749N/A *
749N/A ****************************************************************/
749N/A
749N/Astatic void GetGCs(w)
749N/AWidget w;
749N/A{
749N/A XGCValues values;
749N/A ListWidget lw = (ListWidget) w;
749N/A
749N/A values.foreground = lw->list.foreground;
749N/A values.font = lw->list.font->fid;
749N/A
749N/A if ( lw->simple.international == True )
749N/A lw->list.normgc = XtAllocateGC( w, 0, (unsigned) GCForeground,
749N/A &values, GCFont, 0 );
749N/A else
749N/A lw->list.normgc = XtGetGC( w, (unsigned) GCForeground | GCFont,
749N/A &values);
749N/A
749N/A values.foreground = lw->core.background_pixel;
749N/A
749N/A if ( lw->simple.international == True )
749N/A lw->list.revgc = XtAllocateGC( w, 0, (unsigned) GCForeground,
749N/A &values, GCFont, 0 );
749N/A else
749N/A lw->list.revgc = XtGetGC( w, (unsigned) GCForeground | GCFont,
749N/A &values);
749N/A
749N/A values.tile = XmuCreateStippledPixmap(XtScreen(w),
749N/A lw->list.foreground,
749N/A lw->core.background_pixel,
749N/A lw->core.depth);
749N/A values.fill_style = FillTiled;
749N/A
749N/A if ( lw->simple.international == True )
749N/A lw->list.graygc = XtAllocateGC( w, 0, (unsigned) GCTile | GCFillStyle,
749N/A &values, GCFont, 0 );
749N/A else
749N/A lw->list.graygc = XtGetGC( w, (unsigned) GCFont | GCTile | GCFillStyle,
749N/A &values);
749N/A}
749N/A
749N/A
749N/A/* CalculatedValues()
749N/A *
749N/A * does routine checks/computations that must be done after data changes
749N/A * but won't hurt if accidently called
749N/A *
749N/A * These calculations were needed in SetValues. They were in ResetList.
749N/A * ResetList called ChangeSize, which made an XtGeometryRequest. You
749N/A * MAY NOT change your geometry from within a SetValues. (Xt man,
749N/A * sect. 9.7.2) So, I factored these changes out. */
749N/A
749N/Astatic void CalculatedValues( w )
749N/AWidget w;
749N/A{
749N/A int i, len;
749N/A
749N/A ListWidget lw = (ListWidget) w;
749N/A
749N/A /* If list is NULL then the list will just be the name of the widget. */
749N/A
749N/A if (lw->list.list == NULL) {
749N/A lw->list.list = &(lw->core.name);
749N/A lw->list.nitems = 1;
749N/A }
749N/A
749N/A /* Get number of items. */
749N/A
749N/A if (lw->list.nitems == 0)
749N/A for ( ; lw->list.list[lw->list.nitems] != NULL ; lw->list.nitems++);
749N/A
749N/A /* Get column width. */
749N/A
749N/A if ( LongestFree( lw ) ) {
749N/A
749N/A lw->list.longest = 0; /* so it will accumulate real longest below */
749N/A
749N/A for ( i = 0 ; i < lw->list.nitems; i++) {
749N/A if ( lw->simple.international == True )
749N/A len = XmbTextEscapement(lw->list.fontset, lw->list.list[i],
749N/A strlen(lw->list.list[i]));
749N/A else
749N/A len = XTextWidth(lw->list.font, lw->list.list[i],
749N/A strlen(lw->list.list[i]));
749N/A if (len > lw->list.longest)
749N/A lw->list.longest = len;
749N/A }
749N/A }
749N/A
749N/A lw->list.col_width = lw->list.longest + lw->list.column_space;
749N/A}
749N/A
749N/A/* Function Name: ResetList
749N/A * Description: Resets the new list when important things change.
749N/A * Arguments: w - the widget.
749N/A * changex, changey - allow the height or width to change?
749N/A *
749N/A * Returns: TRUE if width or height have been changed
749N/A */
749N/A
749N/Astatic void
749N/AResetList( w, changex, changey )
749N/AWidget w;
749N/ABoolean changex, changey;
749N/A{
749N/A Dimension width = w->core.width;
749N/A Dimension height = w->core.height;
749N/A
749N/A CalculatedValues( w );
749N/A
749N/A if( Layout( w, changex, changey, &width, &height ) )
749N/A ChangeSize( w, width, height );
749N/A}
749N/A
749N/A/* Function Name: ChangeSize.
749N/A * Description: Laysout the widget.
749N/A * Arguments: w - the widget to try change the size of.
749N/A * Returns: none.
749N/A */
749N/A
749N/Astatic void
749N/AChangeSize(w, width, height)
749N/AWidget w;
749N/ADimension width, height;
749N/A{
749N/A XtWidgetGeometry request, reply;
749N/A
749N/A request.request_mode = CWWidth | CWHeight;
749N/A request.width = width;
749N/A request.height = height;
749N/A
749N/A switch ( XtMakeGeometryRequest(w, &request, &reply) ) {
749N/A case XtGeometryYes:
749N/A break;
749N/A case XtGeometryNo:
749N/A break;
749N/A case XtGeometryAlmost:
749N/A Layout(w, (request.height != reply.height),
749N/A (request.width != reply.width),
749N/A &(reply.width), &(reply.height));
749N/A request = reply;
749N/A switch (XtMakeGeometryRequest(w, &request, &reply) ) {
749N/A case XtGeometryYes:
749N/A case XtGeometryNo:
749N/A break;
749N/A case XtGeometryAlmost:
749N/A request = reply;
749N/A Layout(w, FALSE, FALSE, &(request.width), &(request.height));
749N/A request.request_mode = CWWidth | CWHeight;
749N/A XtMakeGeometryRequest(w, &request, &reply);
749N/A break;
749N/A default:
749N/A XtAppWarning(XtWidgetToApplicationContext(w),
749N/A "List Widget: Unknown geometry return.");
749N/A break;
749N/A }
749N/A break;
749N/A default:
749N/A XtAppWarning(XtWidgetToApplicationContext(w),
749N/A "List Widget: Unknown geometry return.");
749N/A break;
749N/A }
749N/A}
749N/A
749N/A/* Function Name: Initialize
749N/A * Description: Function that initilizes the widget instance.
749N/A * Arguments: junk - NOT USED.
749N/A * new - the new widget.
749N/A * Returns: none
749N/A */
749N/A
749N/A/* ARGSUSED */
749N/Astatic void
749N/AInitialize(junk, new, args, num_args)
749N/AWidget junk, new;
749N/AArgList args;
749N/ACardinal *num_args;
749N/A{
749N/A ListWidget lw = (ListWidget) new;
749N/A
749N/A/*
749N/A * Initialize all private resources.
749N/A */
749N/A
749N/A /* record for posterity if we are free */
749N/A lw->list.freedoms = (lw->core.width != 0) * WidthLock +
749N/A (lw->core.height != 0) * HeightLock +
749N/A (lw->list.longest != 0) * LongestLock;
749N/A
749N/A GetGCs(new);
749N/A
749N/A /* Set row height. based on font or fontset */
749N/A
749N/A if (lw->simple.international == True )
749N/A lw->list.row_height =
749N/A XExtentsOfFontSet(lw->list.fontset)->max_ink_extent.height
749N/A + lw->list.row_space;
749N/A else
749N/A lw->list.row_height = lw->list.font->max_bounds.ascent
749N/A + lw->list.font->max_bounds.descent
749N/A + lw->list.row_space;
749N/A
749N/A ResetList( new, WidthFree( lw ), HeightFree( lw ) );
749N/A
749N/A lw->list.highlight = lw->list.is_highlighted = NO_HIGHLIGHT;
749N/A
749N/A} /* Initialize */
749N/A
749N/A/* Function Name: CvtToItem
749N/A * Description: Converts Xcoord to item number of item containing that
749N/A * point.
749N/A * Arguments: w - the list widget.
749N/A * xloc, yloc - x location, and y location.
749N/A * Returns: the item number.
749N/A */
749N/A
749N/Astatic int
749N/ACvtToItem(w, xloc, yloc, item)
749N/AWidget w;
749N/Aint xloc, yloc;
749N/Aint *item;
749N/A{
749N/A int one, another;
749N/A ListWidget lw = (ListWidget) w;
749N/A int ret_val = OKAY;
749N/A
749N/A if (lw->list.vertical_cols) {
749N/A one = lw->list.nrows * ((xloc - (int) lw->list.internal_width)
749N/A / lw->list.col_width);
749N/A another = (yloc - (int) lw->list.internal_height)
749N/A / lw->list.row_height;
749N/A /* If out of range, return minimum possible value. */
749N/A if (another >= lw->list.nrows) {
749N/A another = lw->list.nrows - 1;
749N/A ret_val = OUT_OF_RANGE;
749N/A }
749N/A }
749N/A else {
749N/A one = (lw->list.ncols * ((yloc - (int) lw->list.internal_height)
749N/A / lw->list.row_height)) ;
749N/A /* If in right margin handle things right. */
749N/A another = (xloc - (int) lw->list.internal_width) / lw->list.col_width;
749N/A if (another >= lw->list.ncols) {
749N/A another = lw->list.ncols - 1;
749N/A ret_val = OUT_OF_RANGE;
749N/A }
749N/A }
749N/A if ((xloc < 0) || (yloc < 0))
749N/A ret_val = OUT_OF_RANGE;
749N/A if (one < 0) one = 0;
749N/A if (another < 0) another = 0;
749N/A *item = one + another;
749N/A if (*item >= lw->list.nitems) return(OUT_OF_RANGE);
749N/A return(ret_val);
749N/A}
749N/A
749N/A/* Function Name: FindCornerItems.
749N/A * Description: Find the corners of the rectangle in item space.
749N/A * Arguments: w - the list widget.
749N/A * event - the event structure that has the rectangle it it.
749N/A * ul_ret, lr_ret - the corners ** RETURNED **.
749N/A * Returns: none.
749N/A */
749N/A
749N/Astatic void
749N/AFindCornerItems(w, event, ul_ret, lr_ret)
749N/AWidget w;
749N/AXEvent * event;
749N/Aint *ul_ret, *lr_ret;
749N/A{
749N/A int xloc, yloc;
749N/A
749N/A xloc = event->xexpose.x;
749N/A yloc = event->xexpose.y;
749N/A CvtToItem(w, xloc, yloc, ul_ret);
749N/A xloc += event->xexpose.width;
749N/A yloc += event->xexpose.height;
749N/A CvtToItem(w, xloc, yloc, lr_ret);
749N/A}
749N/A
749N/A/* Function Name: ItemInRectangle
749N/A * Description: returns TRUE if the item passed is in the given rectangle.
749N/A * Arguments: w - the list widget.
749N/A * ul, lr - corners of the rectangle in item space.
749N/A * item - item to check.
749N/A * Returns: TRUE if the item passed is in the given rectangle.
749N/A */
749N/A
749N/Astatic Boolean
749N/AItemInRectangle(w, ul, lr, item)
749N/AWidget w;
749N/Aint ul, lr, item;
749N/A{
749N/A ListWidget lw = (ListWidget) w;
749N/A int mod_item;
749N/A int things;
749N/A
749N/A if (item < ul || item > lr)
749N/A return(FALSE);
749N/A if (lw->list.vertical_cols)
749N/A things = lw->list.nrows;
749N/A else
749N/A things = lw->list.ncols;
749N/A
749N/A mod_item = item % things;
749N/A if ( (mod_item >= ul % things) && (mod_item <= lr % things ) )
749N/A return(TRUE);
749N/A return(FALSE);
749N/A}
749N/A
749N/A
749N/A/* HighlightBackground()
749N/A *
749N/A * Paints the color of the background for the given item. It performs
749N/A * clipping to the interior of internal_width/height by hand, as its a
749N/A * simple calculation and probably much faster than using Xlib and a clip mask.
749N/A *
749N/A * x, y - ul corner of the area item occupies.
749N/A * gc - the gc to use to paint this rectangle */
749N/A
749N/Astatic void
749N/AHighlightBackground( w, x, y, gc )
749N/AWidget w;
749N/Aint x, y;
749N/AGC gc;
749N/A{
749N/A ListWidget lw = (ListWidget) w;
749N/A
749N/A /* easy to clip the rectangle by hand and probably alot faster than Xlib */
749N/A
749N/A Dimension width = lw->list.col_width;
749N/A Dimension height = lw->list.row_height;
749N/A Dimension frame_limited_width = w->core.width - lw->list.internal_width - x;
749N/A Dimension frame_limited_height= w->core.height- lw->list.internal_height- y;
749N/A
749N/A /* Clip the rectangle width and height to the edge of the drawable area */
749N/A
749N/A if ( width > frame_limited_width )
749N/A width = frame_limited_width;
749N/A if ( height> frame_limited_height)
749N/A height = frame_limited_height;
749N/A
749N/A /* Clip the rectangle x and y to the edge of the drawable area */
749N/A
749N/A if ( x < lw->list.internal_width ) {
749N/A width = width - ( lw->list.internal_width - x );
749N/A x = lw->list.internal_width;
749N/A }
749N/A if ( y < lw->list.internal_height) {
749N/A height = height - ( lw->list.internal_height - x );
749N/A y = lw->list.internal_height;
749N/A }
749N/A XFillRectangle( XtDisplay( w ), XtWindow( w ), gc, x, y,
749N/A width, height );
749N/A}
749N/A
749N/A
749N/A/* ClipToShadowInteriorAndLongest()
749N/A *
749N/A * Converts the passed gc so that any drawing done with that GC will not
749N/A * write in the empty margin (specified by internal_width/height) (which also
749N/A * prevents erasing the shadow. It also clips against the value longest.
749N/A * If the user doesn't set longest, this has no effect (as longest is the
749N/A * maximum of all item lengths). If the user does specify, say, 80 pixel
749N/A * columns, though, this prevents items from overwriting other items. */
749N/A
749N/Astatic void ClipToShadowInteriorAndLongest(lw, gc_p, x)
749N/A ListWidget lw;
749N/A GC* gc_p;
749N/A Dimension x;
749N/A{
749N/A XRectangle rect;
749N/A
749N/A rect.x = x;
749N/A rect.y = lw->list.internal_height;
749N/A rect.height = lw->core.height - lw->list.internal_height * 2;
749N/A rect.width = lw->core.width - lw->list.internal_width - x;
749N/A if ( rect.width > lw->list.longest )
749N/A rect.width = lw->list.longest;
749N/A
749N/A XSetClipRectangles( XtDisplay((Widget)lw),*gc_p,0,0,&rect,1,YXBanded );
749N/A}
749N/A
749N/A
749N/A/* PaintItemName()
749N/A *
749N/A * paints the name of the item in the appropriate location.
749N/A * w - the list widget.
749N/A * item - the item to draw.
749N/A *
749N/A * NOTE: no action taken on an unrealized widget. */
749N/A
749N/Astatic void
749N/APaintItemName(w, item)
749N/AWidget w;
749N/Aint item;
749N/A{
749N/A char * str;
749N/A GC gc;
749N/A int x, y, str_y;
749N/A ListWidget lw = (ListWidget) w;
749N/A XFontSetExtents *ext = XExtentsOfFontSet(lw->list.fontset);
749N/A
749N/A if (!XtIsRealized(w)) return; /* Just in case... */
749N/A
749N/A if (lw->list.vertical_cols) {
749N/A x = lw->list.col_width * (item / lw->list.nrows)
749N/A + lw->list.internal_width;
749N/A y = lw->list.row_height * (item % lw->list.nrows)
749N/A + lw->list.internal_height;
749N/A }
749N/A else {
749N/A x = lw->list.col_width * (item % lw->list.ncols)
749N/A + lw->list.internal_width;
749N/A y = lw->list.row_height * (item / lw->list.ncols)
749N/A + lw->list.internal_height;
749N/A }
749N/A
749N/A if ( lw->simple.international == True )
749N/A str_y = y + abs(ext->max_ink_extent.y);
749N/A else
749N/A str_y = y + lw->list.font->max_bounds.ascent;
749N/A
749N/A if (item == lw->list.is_highlighted) {
749N/A if (item == lw->list.highlight) {
749N/A gc = lw->list.revgc;
749N/A HighlightBackground(w, x, y, lw->list.normgc);
749N/A }
749N/A else {
749N/A if (XtIsSensitive(w))
749N/A gc = lw->list.normgc;
749N/A else
749N/A gc = lw->list.graygc;
749N/A HighlightBackground(w, x, y, lw->list.revgc);
749N/A lw->list.is_highlighted = NO_HIGHLIGHT;
749N/A }
749N/A }
749N/A else {
749N/A if (item == lw->list.highlight) {
749N/A gc = lw->list.revgc;
749N/A HighlightBackground(w, x, y, lw->list.normgc);
749N/A lw->list.is_highlighted = item;
749N/A }
749N/A else {
749N/A if (XtIsSensitive(w))
749N/A gc = lw->list.normgc;
749N/A else
749N/A gc = lw->list.graygc;
749N/A }
749N/A }
749N/A
749N/A /* List's overall width contains the same number of inter-column
749N/A column_space's as columns. There should thus be a half
749N/A column_width margin on each side of each column.
749N/A The row case is symmetric. */
749N/A
749N/A x += lw->list.column_space / 2;
749N/A str_y += lw->list.row_space / 2;
749N/A
749N/A str = lw->list.list[item]; /* draw it */
749N/A
749N/A ClipToShadowInteriorAndLongest( lw, &gc, x );
749N/A
749N/A if ( lw->simple.international == True )
749N/A XmbDrawString( XtDisplay( w ), XtWindow( w ), lw->list.fontset,
749N/A gc, x, str_y, str, strlen( str ) );
749N/A else
749N/A XDrawString( XtDisplay( w ), XtWindow( w ),
749N/A gc, x, str_y, str, strlen( str ) );
749N/A
749N/A XSetClipMask( XtDisplay( w ), gc, None );
749N/A}
749N/A
749N/A
749N/A/* Redisplay()
749N/A *
749N/A * Repaints the widget window on expose events.
749N/A * w - the list widget.
749N/A * event - the expose event for this repaint.
749N/A * junk - not used, unless three-d patch enabled. */
749N/A
749N/A/* ARGSUSED */
749N/Astatic void
749N/ARedisplay(w, event, junk)
749N/AWidget w;
749N/AXEvent *event;
749N/ARegion junk;
749N/A{
749N/A int item; /* an item to work with. */
749N/A int ul_item, lr_item; /* corners of items we need to paint. */
749N/A ListWidget lw = (ListWidget) w;
749N/A
749N/A if (event == NULL) { /* repaint all. */
749N/A ul_item = 0;
749N/A lr_item = lw->list.nrows * lw->list.ncols - 1;
749N/A XClearWindow(XtDisplay(w), XtWindow(w));
749N/A }
749N/A else
749N/A FindCornerItems(w, event, &ul_item, &lr_item);
749N/A
749N/A for (item = ul_item; (item <= lr_item && item < lw->list.nitems) ; item++)
749N/A if (ItemInRectangle(w, ul_item, lr_item, item))
749N/A PaintItemName(w, item);
749N/A}
749N/A
749N/A
749N/A/* PreferredGeom()
749N/A *
749N/A * This tells the parent what size we would like to be
749N/A * given certain constraints.
749N/A * w - the widget.
749N/A * intended - what the parent intends to do with us.
749N/A * requested - what we want to happen. */
749N/A
749N/Astatic XtGeometryResult
749N/APreferredGeom(w, intended, requested)
749N/AWidget w;
749N/AXtWidgetGeometry *intended, *requested;
749N/A{
749N/A Dimension new_width, new_height;
749N/A Boolean change, width_req, height_req;
749N/A
749N/A width_req = intended->request_mode & CWWidth;
749N/A height_req = intended->request_mode & CWHeight;
749N/A
749N/A if (width_req)
749N/A new_width = intended->width;
749N/A else
749N/A new_width = w->core.width;
749N/A
749N/A if (height_req)
749N/A new_height = intended->height;
749N/A else
749N/A new_height = w->core.height;
749N/A
749N/A requested->request_mode = 0;
749N/A
749N/A/*
749N/A * We only care about our height and width.
749N/A */
749N/A
749N/A if ( !width_req && !height_req)
749N/A return(XtGeometryYes);
749N/A
749N/A change = Layout(w, !width_req, !height_req, &new_width, &new_height);
749N/A
749N/A requested->request_mode |= CWWidth;
749N/A requested->width = new_width;
749N/A requested->request_mode |= CWHeight;
749N/A requested->height = new_height;
749N/A
749N/A if (change)
749N/A return(XtGeometryAlmost);
749N/A return(XtGeometryYes);
749N/A}
749N/A
749N/A
749N/A/* Resize()
749N/A *
749N/A * resizes the widget, by changing the number of rows and columns. */
749N/A
749N/Astatic void
749N/AResize(w)
749N/A Widget w;
749N/A{
749N/A Dimension width, height;
749N/A
749N/A width = w->core.width;
749N/A height = w->core.height;
749N/A
749N/A if (Layout(w, FALSE, FALSE, &width, &height))
749N/A XtAppWarning(XtWidgetToApplicationContext(w),
749N/A "List Widget: Size changed when it shouldn't have when resising.");
749N/A}
749N/A
749N/A
749N/A/* Layout()
749N/A *
749N/A * lays out the item in the list.
749N/A * w - the widget.
749N/A * xfree, yfree - TRUE if we are free to resize the widget in
749N/A * this direction.
749N/A * width, height- the is the current width and height that we are going
749N/A * we are going to layout the list widget to,
749N/A * depending on xfree and yfree of course.
749N/A *
749N/A * RETURNS: TRUE if width or height have been changed. */
749N/A
749N/Astatic Boolean
749N/ALayout(w, xfree, yfree, width, height)
749N/AWidget w;
749N/ABoolean xfree, yfree;
749N/ADimension *width, *height;
749N/A{
749N/A ListWidget lw = (ListWidget) w;
749N/A Boolean change = FALSE;
749N/A
749N/A/*
749N/A * If force columns is set then always use number of columns specified
749N/A * by default_cols.
749N/A */
749N/A
749N/A if (lw->list.force_cols) {
749N/A lw->list.ncols = lw->list.default_cols;
749N/A if (lw->list.ncols <= 0) lw->list.ncols = 1;
749N/A /* 12/3 = 4 and 10/3 = 4, but 9/3 = 3 */
749N/A lw->list.nrows = ( ( lw->list.nitems - 1) / lw->list.ncols) + 1 ;
749N/A if (xfree) { /* If allowed resize width. */
749N/A
749N/A /* this counts the same number
749N/A of inter-column column_space 's as columns. There should thus be a
749N/A half column_space margin on each side of each column...*/
749N/A
749N/A *width = lw->list.ncols * lw->list.col_width
749N/A + 2 * lw->list.internal_width;
749N/A change = TRUE;
749N/A }
749N/A if (yfree) { /* If allowed resize height. */
749N/A *height = (lw->list.nrows * lw->list.row_height)
749N/A + 2 * lw->list.internal_height;
749N/A change = TRUE;
749N/A }
749N/A return(change);
749N/A }
749N/A
749N/A/*
749N/A * If both width and height are free to change the use default_cols
749N/A * to determine the number columns and set new width and height to
749N/A * just fit the window.
749N/A */
749N/A
749N/A if (xfree && yfree) {
749N/A lw->list.ncols = lw->list.default_cols;
749N/A if (lw->list.ncols <= 0) lw->list.ncols = 1;
749N/A lw->list.nrows = ( ( lw->list.nitems - 1) / lw->list.ncols) + 1 ;
749N/A *width = lw->list.ncols * lw->list.col_width
749N/A + 2 * lw->list.internal_width;
749N/A *height = (lw->list.nrows * lw->list.row_height)
749N/A + 2 * lw->list.internal_height;
749N/A change = TRUE;
749N/A }
749N/A/*
749N/A * If the width is fixed then use it to determine the number of columns.
749N/A * If the height is free to move (width still fixed) then resize the height
749N/A * of the widget to fit the current list exactly.
749N/A */
749N/A else if (!xfree) {
749N/A lw->list.ncols = ( (int)(*width - 2 * lw->list.internal_width)
749N/A / (int)lw->list.col_width);
749N/A if (lw->list.ncols <= 0) lw->list.ncols = 1;
749N/A lw->list.nrows = ( ( lw->list.nitems - 1) / lw->list.ncols) + 1 ;
749N/A if ( yfree ) {
749N/A *height = (lw->list.nrows * lw->list.row_height)
749N/A + 2 * lw->list.internal_height;
749N/A change = TRUE;
749N/A }
749N/A }
749N/A/*
749N/A * The last case is xfree and !yfree we use the height to determine
749N/A * the number of rows and then set the width to just fit the resulting
749N/A * number of columns.
749N/A */
749N/A else if (!yfree) { /* xfree must be TRUE. */
749N/A lw->list.nrows = (int)(*height - 2 * lw->list.internal_height)
749N/A / (int)lw->list.row_height;
749N/A if (lw->list.nrows <= 0) lw->list.nrows = 1;
749N/A lw->list.ncols = (( lw->list.nitems - 1 ) / lw->list.nrows) + 1;
749N/A *width = lw->list.ncols * lw->list.col_width
749N/A + 2 * lw->list.internal_width;
749N/A change = TRUE;
749N/A }
749N/A return(change);
749N/A}
749N/A
749N/A
749N/A/* Notify() - ACTION
749N/A *
749N/A * Notifies the user that a button has been pressed, and
749N/A * calls the callback; if the XtNpasteBuffer resource is true
749N/A * then the name of the item is also put in CUT_BUFFER0. */
749N/A
749N/A/* ARGSUSED */
749N/Astatic void
749N/ANotify(w, event, params, num_params)
749N/AWidget w;
749N/AXEvent * event;
749N/AString * params;
749N/ACardinal *num_params;
749N/A{
749N/A ListWidget lw = ( ListWidget ) w;
749N/A int item, item_len;
749N/A XawListReturnStruct ret_value;
749N/A
749N/A/*
749N/A * Find item and if out of range then unhighlight and return.
749N/A *
749N/A * If the current item is unhighlighted then the user has aborted the
749N/A * notify, so unhighlight and return.
749N/A */
749N/A
749N/A if ( ((CvtToItem(w, event->xbutton.x, event->xbutton.y, &item))
749N/A == OUT_OF_RANGE) || (lw->list.highlight != item) ) {
749N/A XawListUnhighlight(w);
749N/A return;
749N/A }
749N/A
749N/A item_len = strlen(lw->list.list[item]);
749N/A
749N/A if ( lw->list.paste ) /* if XtNpasteBuffer set then paste it. */
749N/A XStoreBytes(XtDisplay(w), lw->list.list[item], item_len);
749N/A
749N/A/*
749N/A * Call Callback function.
749N/A */
749N/A
749N/A ret_value.string = lw->list.list[item];
749N/A ret_value.list_index = item;
749N/A
749N/A XtCallCallbacks( w, XtNcallback, (XtPointer) &ret_value);
749N/A}
749N/A
749N/A
749N/A/* Unset() - ACTION
749N/A *
749N/A * unhighlights the current element. */
749N/A
749N/A/* ARGSUSED */
749N/Astatic void
749N/AUnset(w, event, params, num_params)
749N/AWidget w;
749N/AXEvent * event;
749N/AString * params;
749N/ACardinal *num_params;
749N/A{
749N/A XawListUnhighlight(w);
749N/A}
749N/A
749N/A
749N/A/* Set() - ACTION
749N/A *
749N/A * Highlights the current element. */
749N/A
749N/A/* ARGSUSED */
749N/Astatic void
749N/ASet(w, event, params, num_params)
749N/AWidget w;
749N/AXEvent * event;
749N/AString * params;
749N/ACardinal *num_params;
749N/A{
749N/A int item;
749N/A ListWidget lw = (ListWidget) w;
749N/A
749N/A if ( (CvtToItem(w, event->xbutton.x, event->xbutton.y, &item))
749N/A == OUT_OF_RANGE)
749N/A XawListUnhighlight(w); /* Unhighlight current item. */
749N/A else if ( lw->list.is_highlighted != item ) /* If this item is not */
749N/A XawListHighlight(w, item); /* highlighted then do it. */
749N/A}
749N/A
749N/A/*
749N/A * Set specified arguments into widget
749N/A */
749N/A
749N/Astatic Boolean
749N/ASetValues(current, request, new, args, num_args)
749N/AWidget current, request, new;
749N/AArgList args;
749N/ACardinal *num_args;
749N/A{
749N/A ListWidget cl = (ListWidget) current;
749N/A ListWidget rl = (ListWidget) request;
749N/A ListWidget nl = (ListWidget) new;
749N/A Boolean redraw = FALSE;
749N/A XFontSetExtents *ext = XExtentsOfFontSet(nl->list.fontset);
749N/A
749N/A /* If the request height/width is different, lock it. Unless its 0. If */
749N/A /* neither new nor 0, leave it as it was. Not in R5. */
749N/A if ( nl->core.width != cl->core.width )
749N/A nl->list.freedoms |= WidthLock;
749N/A if ( nl->core.width == 0 )
749N/A nl->list.freedoms &= ~WidthLock;
749N/A
749N/A if ( nl->core.height != cl->core.height )
749N/A nl->list.freedoms |= HeightLock;
749N/A if ( nl->core.height == 0 )
749N/A nl->list.freedoms &= ~HeightLock;
749N/A
749N/A if ( nl->list.longest != cl->list.longest )
749N/A nl->list.freedoms |= LongestLock;
749N/A if ( nl->list.longest == 0 )
749N/A nl->list.freedoms &= ~LongestLock;
749N/A
749N/A /* _DONT_ check for fontset here - it's not in GC.*/
749N/A
749N/A if ( (cl->list.foreground != nl->list.foreground) ||
749N/A (cl->core.background_pixel != nl->core.background_pixel) ||
749N/A (cl->list.font != nl->list.font) ) {
749N/A XGCValues values;
749N/A XGetGCValues(XtDisplay(current), cl->list.graygc, GCTile, &values);
749N/A XmuReleaseStippledPixmap(XtScreen(current), values.tile);
749N/A XtReleaseGC(current, cl->list.graygc);
749N/A XtReleaseGC(current, cl->list.revgc);
749N/A XtReleaseGC(current, cl->list.normgc);
749N/A GetGCs(new);
749N/A redraw = TRUE;
749N/A }
749N/A
749N/A if ( ( cl->list.font != nl->list.font ) &&
749N/A ( cl->simple.international == False ) )
749N/A nl->list.row_height = nl->list.font->max_bounds.ascent
749N/A + nl->list.font->max_bounds.descent
749N/A + nl->list.row_space;
749N/A
749N/A else if ( ( cl->list.fontset != nl->list.fontset ) &&
749N/A ( cl->simple.international == True ) )
749N/A nl->list.row_height = ext->max_ink_extent.height + nl->list.row_space;
749N/A
749N/A /* ...If the above two font(set) change checkers above both failed, check
749N/A if row_space was altered. If one of the above passed, row_height will
749N/A already have been re-calculated. */
749N/A
749N/A else if ( cl->list.row_space != nl->list.row_space ) {
749N/A
749N/A if (cl->simple.international == True )
749N/A nl->list.row_height = ext->max_ink_extent.height + nl->list.row_space;
749N/A else
749N/A nl->list.row_height = nl->list.font->max_bounds.ascent
749N/A + nl->list.font->max_bounds.descent
749N/A + nl->list.row_space;
749N/A }
749N/A
749N/A if ((cl->core.width != nl->core.width) ||
749N/A (cl->core.height != nl->core.height) ||
749N/A (cl->list.internal_width != nl->list.internal_width) ||
749N/A (cl->list.internal_height != nl->list.internal_height) ||
749N/A (cl->list.column_space != nl->list.column_space) ||
749N/A (cl->list.row_space != nl->list.row_space) ||
749N/A (cl->list.default_cols != nl->list.default_cols) ||
749N/A ( (cl->list.force_cols != nl->list.force_cols) &&
749N/A (rl->list.force_cols != nl->list.ncols) ) ||
749N/A (cl->list.vertical_cols != nl->list.vertical_cols) ||
749N/A (cl->list.longest != nl->list.longest) ||
749N/A (cl->list.nitems != nl->list.nitems) ||
749N/A (cl->list.font != nl->list.font) ||
749N/A /* Equiv. fontsets might have different values, but the same fonts, so the
749N/A next comparison is sloppy but not dangerous. */
749N/A (cl->list.fontset != nl->list.fontset) ||
749N/A (cl->list.list != nl->list.list) ) {
749N/A
749N/A CalculatedValues( new );
749N/A Layout( new, WidthFree( nl ), HeightFree( nl ),
749N/A &nl->core.width, &nl->core.height );
749N/A redraw = TRUE;
749N/A }
749N/A
749N/A if (cl->list.list != nl->list.list)
749N/A nl->list.is_highlighted = nl->list.highlight = NO_HIGHLIGHT;
749N/A
749N/A if ((cl->core.sensitive != nl->core.sensitive) ||
749N/A (cl->core.ancestor_sensitive != nl->core.ancestor_sensitive)) {
749N/A nl->list.highlight = NO_HIGHLIGHT;
749N/A redraw = TRUE;
749N/A }
749N/A
749N/A if (!XtIsRealized(current))
749N/A return(FALSE);
749N/A
749N/A return(redraw);
749N/A}
749N/A
749N/Astatic void Destroy(w)
749N/A Widget w;
749N/A{
749N/A ListWidget lw = (ListWidget) w;
749N/A XGCValues values;
749N/A
749N/A XGetGCValues(XtDisplay(w), lw->list.graygc, GCTile, &values);
749N/A XmuReleaseStippledPixmap(XtScreen(w), values.tile);
749N/A XtReleaseGC(w, lw->list.graygc);
749N/A XtReleaseGC(w, lw->list.revgc);
749N/A XtReleaseGC(w, lw->list.normgc);
749N/A}
749N/A
749N/A/* Exported Functions */
749N/A
749N/A/* Function Name: XawListChange.
749N/A * Description: Changes the list being used and shown.
749N/A * Arguments: w - the list widget.
749N/A * list - the new list.
749N/A * nitems - the number of items in the list.
749N/A * longest - the length (in Pixels) of the longest element
749N/A * in the list.
749N/A * resize - if TRUE the the list widget will
749N/A * try to resize itself.
749N/A * Returns: none.
749N/A * NOTE: If nitems of longest are <= 0 then they will be calculated.
749N/A * If nitems is <= 0 then the list needs to be NULL terminated.
749N/A */
749N/A
749N/Avoid
749N/A#if NeedFunctionPrototypes
749N/AXawListChange(Widget w, char ** list, int nitems, int longest,
749N/A#if NeedWidePrototypes
749N/A int resize_it)
749N/A#else
749N/A Boolean resize_it)
749N/A#endif
749N/A#else
749N/AXawListChange(w, list, nitems, longest, resize_it)
749N/AWidget w;
749N/Achar ** list;
749N/Aint nitems, longest;
749N/ABoolean resize_it;
749N/A#endif
749N/A{
749N/A ListWidget lw = (ListWidget) w;
749N/A Dimension new_width = w->core.width;
749N/A Dimension new_height = w->core.height;
749N/A
749N/A lw->list.list = list;
749N/A
749N/A if ( nitems <= 0 ) nitems = 0;
749N/A lw->list.nitems = nitems;
749N/A if ( longest <= 0 ) longest = 0;
749N/A
749N/A /* If the user passes 0 meaning "calculate it", it must be free */
749N/A if ( longest != 0 )
749N/A lw->list.freedoms |= LongestLock;
749N/A else /* the user's word is god. */
749N/A lw->list.freedoms &= ~LongestLock;
749N/A
749N/A if ( resize_it )
749N/A lw->list.freedoms &= ~WidthLock & ~HeightLock;
749N/A /* else - still resize if its not locked */
749N/A
749N/A lw->list.longest = longest;
749N/A
749N/A CalculatedValues( w );
749N/A
749N/A if( Layout( w, WidthFree( w ), HeightFree( w ),
749N/A &new_width, &new_height ) )
749N/A ChangeSize( w, new_width, new_height );
749N/A
749N/A lw->list.is_highlighted = lw->list.highlight = NO_HIGHLIGHT;
749N/A if ( XtIsRealized( w ) )
749N/A Redisplay( w, (XEvent *)NULL, (Region)NULL );
749N/A}
749N/A
749N/A/* Function Name: XawListUnhighlight
749N/A * Description: unlights the current highlighted element.
749N/A * Arguments: w - the widget.
749N/A * Returns: none.
749N/A */
749N/A
749N/Avoid
749N/A#if NeedFunctionPrototypes
749N/AXawListUnhighlight(Widget w)
749N/A#else
749N/AXawListUnhighlight(w)
749N/AWidget w;
749N/A#endif
749N/A{
749N/A ListWidget lw = ( ListWidget ) w;
749N/A
749N/A lw->list.highlight = NO_HIGHLIGHT;
749N/A if (lw->list.is_highlighted != NO_HIGHLIGHT)
749N/A PaintItemName(w, lw->list.is_highlighted); /* unhighlight this one. */
749N/A}
749N/A
749N/A/* Function Name: XawListHighlight
749N/A * Description: Highlights the given item.
749N/A * Arguments: w - the list widget.
749N/A * item - the item to hightlight.
749N/A * Returns: none.
749N/A */
749N/A
749N/Avoid
749N/A#if NeedFunctionPrototypes
749N/AXawListHighlight(Widget w, int item)
749N/A#else
749N/AXawListHighlight(w, item)
749N/AWidget w;
749N/Aint item;
749N/A#endif
749N/A{
749N/A ListWidget lw = ( ListWidget ) w;
749N/A
749N/A if (XtIsSensitive(w)) {
749N/A lw->list.highlight = item;
749N/A if (lw->list.is_highlighted != NO_HIGHLIGHT)
749N/A PaintItemName(w, lw->list.is_highlighted); /* Unhighlight. */
749N/A PaintItemName(w, item); /* HIGHLIGHT this one. */
749N/A }
749N/A}
749N/A
749N/A/* Function Name: XawListShowCurrent
749N/A * Description: returns the currently highlighted object.
749N/A * Arguments: w - the list widget.
749N/A * Returns: the info about the currently highlighted object.
749N/A */
749N/A
749N/AXawListReturnStruct *
749N/A#if NeedFunctionPrototypes
749N/AXawListShowCurrent(Widget w)
749N/A#else
749N/AXawListShowCurrent(w)
749N/AWidget w;
749N/A#endif
749N/A{
749N/A ListWidget lw = ( ListWidget ) w;
749N/A XawListReturnStruct * ret_val;
749N/A
749N/A ret_val = (XawListReturnStruct *)
749N/A XtMalloc (sizeof (XawListReturnStruct));/* SPARE MALLOC OK */
749N/A
749N/A ret_val->list_index = lw->list.highlight;
749N/A if (ret_val->list_index == XAW_LIST_NONE)
749N/A ret_val->string = "";
749N/A else
749N/A ret_val->string = lw->list.list[ ret_val->list_index ];
749N/A
749N/A return(ret_val);
749N/A}
749N/A