ftp.nice.ch/pub/next/unix/developer/pcn.2.0.s.tar.gz#/contrib/gauge/Xsw/MultiList.c

This is MultiList.c in view mode; [Download] [Up]

#if ( !defined(lint) && !defined(SABER))
  static char PCN_rcsid[] = "$Header: /ufs/comp/mei/PROJ_PCN/onprofile/IFModel/Xsw/RCS/MultiList.c,v 1.1 1992/04/17 18:25:49 mei Exp $";
#endif

/*
 * Copyright 1989 Massachusetts Institute of Technology
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of M.I.T. not be used in advertising or
 * publicity pertaining to distribution of the software without specific,
 * written prior permission.  M.I.T. makes no representations about the
 * suitability of this software for any purpose.  It is provided "as is"
 * without express or implied warranty.
 *
 * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

/*
 * MultiList.c - MultiList widget
 *
 * This is the MultiList widget, it is useful to display a multiList, without the
 * overhead of having a widget for each item in the multiList.  It allows 
 * the user to select an item in a multiList and notifies the application through
 * a callback function.
 *
 *	Created: 	8/13/88
 *	By:		Chris D. Peterson
 *                      MIT X Consortium
 */

#include <stdio.h>
#include <ctype.h>

#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>

#include <X11/Xmu/Drawing.h>

#include <X11/Xaw/XawInit.h>
#include "MultiListP.h"


/* 
 * Default Translation table.
 */

static char defaultTranslations[] =  
  "<Btn1Down>:   Set()Notify()\n\
   <Btn1Motion>:   Move()\n\
  ";

/****************************************************************
 *
 * Full class record constant
 *
 ****************************************************************/

/* Private Data */
#define offset(field) XtOffset(MultiListWidget, field)

static XtResource resources[] = {
    {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
	offset(multiList.foreground), XtRString, "XtDefaultForeground"},
    {XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor),
       offset(simple.cursor), XtRString, "left_ptr"},
    {XtNfont,  XtCFont, XtRFontStruct, sizeof(XFontStruct *),
	offset(multiList.font),XtRString, "XtDefaultFont"},
    {XtNlist, XtCList, XtRPointer, sizeof(char **),
       offset(multiList.list), XtRString, NULL},
    {XtNsingle, XtCSingle, XtRBoolean, sizeof(Boolean),
       offset(multiList.single), XtRString, "True"},
    {XtNdefaultColumns, XtCColumns, XtRInt,  sizeof(int),
	offset(multiList.default_cols), XtRImmediate, (XPointer)2},
    {XtNlongest, XtCLongest, XtRInt,  sizeof(int),
	offset(multiList.longest), XtRImmediate, (XPointer)0},
    {XtNnumberStrings, XtCNumberStrings, XtRInt,  sizeof(int),
	offset(multiList.nitems), XtRImmediate, (XPointer)0},
    {XtNpasteBuffer, XtCBoolean, XtRBoolean,  sizeof(Boolean),
	offset(multiList.paste), XtRString, (XPointer) "False"},
    {XtNforceColumns, XtCColumns, XtRBoolean,  sizeof(Boolean),
	offset(multiList.force_cols), XtRString, (XPointer) "False"},
    {XtNverticalMultiList, XtCBoolean, XtRBoolean,  sizeof(Boolean),
	offset(multiList.vertical_cols), XtRString, (XPointer) "False"},
    {XtNinternalWidth, XtCWidth, XtRDimension,  sizeof(Dimension),
	offset(multiList.internal_width), XtRImmediate, (XPointer)4},
    {XtNinternalHeight, XtCHeight, XtRDimension, sizeof(Dimension),
	offset(multiList.internal_height), XtRImmediate, (XPointer)2},
    {XtNcolumnSpacing, XtCSpacing, XtRDimension,  sizeof(Dimension),
	offset(multiList.column_space), XtRImmediate, (XPointer)6},
    {XtNrowSpacing, XtCSpacing, XtRDimension,  sizeof(Dimension),
	offset(multiList.row_space), XtRImmediate, (XPointer)2},
    {XtNcallback, XtCCallback, XtRCallback, sizeof(XPointer),
        offset(multiList.callback), XtRCallback, NULL},
};

static void Initialize();
static void Destroy();
static void ChangeSize();
static void Resize();
static void Redisplay();
static Boolean Layout();
static XtGeometryResult PreferredGeom();
static Boolean SetValues();
static void Notify(), Set(), Unset(), Move();

static XtActionsRec actions[] = {
      {"Notify",         Notify},
      {"Set",            Set},
      {"Unset",          Unset},
      {"Move",          Move},
      {NULL,NULL}
};

MultiListClassRec multiListClassRec = {
  {
/* core_class fields */	
#define superclass		(&simpleClassRec)
    /* superclass	  	*/	(WidgetClass) superclass,
    /* class_name	  	*/	"MultiList",
    /* widget_size	  	*/	sizeof(MultiListRec),
    /* class_initialize   	*/	XawInitializeWidgetSet,
    /* class_part_initialize	*/	NULL,
    /* class_inited       	*/	FALSE,
    /* initialize	  	*/	Initialize,
    /* initialize_hook		*/	NULL,
    /* realize		  	*/	XtInheritRealize,
    /* actions		  	*/	actions,
    /* num_actions	  	*/	XtNumber(actions),
    /* resources	  	*/	resources,
    /* num_resources	  	*/	XtNumber(resources),
    /* xrm_class	  	*/	NULLQUARK,
    /* compress_motion	  	*/	TRUE,
    /* compress_exposure  	*/	FALSE,
    /* compress_enterleave	*/	TRUE,
    /* visible_interest	  	*/	FALSE,
    /* destroy		  	*/	Destroy,
    /* resize		  	*/	Resize,
    /* expose		  	*/	Redisplay,
    /* set_values	  	*/	SetValues,
    /* set_values_hook		*/	NULL,
    /* set_values_almost	*/	XtInheritSetValuesAlmost,
    /* get_values_hook		*/	NULL,
    /* accept_focus	 	*/	NULL,
    /* version			*/	XtVersion,
    /* callback_private   	*/	NULL,
    /* tm_table		   	*/	defaultTranslations,
   /* query_geometry		*/      PreferredGeom,
  },
/* Simple class fields initialization */
  {
    /* change_sensitive		*/	XtInheritChangeSensitive
  }
};

WidgetClass multiListWidgetClass = (WidgetClass)&multiListClassRec;

/****************************************************************
 *
 * Private Procedures
 *
 ****************************************************************/

static void GetGCs(w)
Widget w;
{
    XGCValues	values;
    MultiListWidget lw = (MultiListWidget) w;    

    values.foreground	= lw->multiList.foreground;
    values.font		= lw->multiList.font->fid;
    lw->multiList.normgc = XtGetGC(w, (unsigned) GCForeground | GCFont,
				 &values);

    values.foreground	= lw->core.background_pixel;
    lw->multiList.revgc = XtGetGC(w, (unsigned) GCForeground | GCFont,
				 &values);

    values.tile       = XmuCreateStippledPixmap(XtScreen(w), 
						lw->multiList.foreground,
						lw->core.background_pixel,
						lw->core.depth);
    values.fill_style = FillTiled;

    lw->multiList.graygc = XtGetGC(w, (unsigned) GCFont | GCTile | GCFillStyle,
			      &values);
}

/*	Function Name: ResetMultiList
 *	Description: Resets the new multiList when important things change.
 *	Arguments: w - the widget.
 *                 changex, changey - allow the height or width to change?
 *	Returns: none.
 */

static void
ResetMultiList(w, changex, changey)
Widget w;
Boolean changex, changey;
{
    MultiListWidget lw = (MultiListWidget) w;
    Dimension width = w->core.width;
    Dimension height = w->core.height;
    register int i, len;

/*
 * If multiList is NULL then the multiList will just be the name of the widget.
 */

    if (lw->multiList.list == NULL) {
      lw->multiList.list = &(lw->core.name);
      lw->multiList.nitems = 1;
    }

    if (lw->multiList.nitems == 0)	    /* Get number of items. */
        for ( ; lw->multiList.list[lw->multiList.nitems] != NULL ; lw->multiList.nitems++);

    if (lw->multiList.longest == 0) /* Get column width. */
        for ( i = 0 ; i < lw->multiList.nitems; i++) {
	    len = XTextWidth(lw->multiList.font, lw->multiList.list[i],
			     strlen(lw->multiList.list[i]));
	    if (len > lw->multiList.longest)
	        lw->multiList.longest = len;
	}

    lw->multiList.col_width = lw->multiList.longest + lw->multiList.column_space;

    if (Layout(w, changex, changey, &width, &height))
      ChangeSize(w, width, height);

    lw->multiList.state = 
      (Boolean *)XtCalloc(lw->multiList.nitems, sizeof(Boolean));
}

/*	Function Name: ChangeSize.
 *	Description: Laysout the widget.
 *	Arguments: w - the widget to try change the size of.
 *	Returns: none.
 */

static void
ChangeSize(w, width, height)
Widget w;
Dimension width, height;
{
    XtWidgetGeometry request, reply;

    request.request_mode = CWWidth | CWHeight;
    request.width = width;
    request.height = height;
    
    switch ( XtMakeGeometryRequest(w, &request, &reply) ) {
    case XtGeometryYes:
    case XtGeometryNo:
        break;
    case XtGeometryAlmost:
	Layout(w, (request.height != reply.height),
	          (request.width != reply.width),
	       &(reply.width), &(reply.height));
	request = reply;
	switch (XtMakeGeometryRequest(w, &request, &reply) ) {
	case XtGeometryYes:
	case XtGeometryNo:
	    break;
	case XtGeometryAlmost:
	    request = reply;
	    if (Layout(w, FALSE, FALSE,
		       &(request.width), &(request.height))) {
	      char buf[BUFSIZ];
	      sprintf(buf, "MultiList Widget: %s %s",
		      "Size Changed when it shouldn't have",
		      "when computing layout");
	      XtAppWarning(XtWidgetToApplicationContext(w), buf);
	    }
	    request.request_mode = CWWidth | CWHeight;
	    XtMakeGeometryRequest(w, &request, &reply);
	    break;
	default:
	  XtAppWarning(XtWidgetToApplicationContext(w),
		       "MultiList Widget: Unknown geometry return.");
	  break;
	}
	break;
    default:
	XtAppWarning(XtWidgetToApplicationContext(w),
		     "MultiList Widget: Unknown geometry return.");
	break;
    }
}

/*	Function Name: Initialize
 *	Description: Function that initilizes the widget instance.
 *	Arguments: junk - NOT USED.
 *                 new  - the new widget.
 *	Returns: none
 */

/* ARGSUSED */
static void 
Initialize(junk, new)
Widget junk, new;
{
    MultiListWidget lw = (MultiListWidget) new;

/* 
 * Initialize all private resources.
 */

    GetGCs(new);

    /* Set row height. */
    lw->multiList.row_height = lw->multiList.font->max_bounds.ascent
			+ lw->multiList.font->max_bounds.descent
			+ lw->multiList.row_space;

    ResetMultiList(new, (new->core.width == 0), (new->core.height == 0));

    lw->multiList.highlight = lw->multiList.is_highlighted = NO_HIGHLIGHT;
} /* Initialize */

/*	Function Name: CvtToItem
 *	Description: Converts Xcoord to item number of item containing that
 *                   point.
 *	Arguments: w - the multiList widget.
 *                 xloc, yloc - x location, and y location.
 *	Returns: the item number.
 */

static int
CvtToItem(w, xloc, yloc, item)
Widget w;
int xloc, yloc;
int *item;
{
    int one, another;
    MultiListWidget lw = (MultiListWidget) w;
    int ret_val = OKAY;

    if (lw->multiList.vertical_cols) {
        one = lw->multiList.nrows * ((xloc - (int) lw->multiList.internal_width)
	    / lw->multiList.col_width);
        another = (yloc - (int) lw->multiList.internal_height) 
	        / lw->multiList.row_height;
	 /* If out of range, return minimum possible value. */
	if (another >= lw->multiList.nrows) {
	    another = lw->multiList.nrows - 1;
	    ret_val = OUT_OF_RANGE;
	}
    }
    else {
        one = (lw->multiList.ncols * ((yloc - (int) lw->multiList.internal_height) 
              / lw->multiList.row_height)) ;
	/* If in right margin handle things right. */
        another = (xloc - (int) lw->multiList.internal_width) / lw->multiList.col_width;
	if (another >= lw->multiList.ncols) {
	    another = lw->multiList.ncols - 1; 
	    ret_val = OUT_OF_RANGE;
	}
    }  
    if ((xloc < 0) || (yloc < 0))
        ret_val = OUT_OF_RANGE;
    if (one < 0) one = 0;
    if (another < 0) another = 0;
    *item = one + another;
    if (*item >= lw->multiList.nitems) return(OUT_OF_RANGE);
    return(ret_val);
}

/*	Function Name: FindmyCornerItems.
 *	Description: Find the corners of the rectangle in item space.
 *	Arguments: w - the multiList widget.
 *                 event - the event structure that has the rectangle it it.
 *                 ul_ret, lr_ret - the corners ** RETURNED **.
 *	Returns: none.
 */

FindmyCornerItems(w, event, ul_ret, lr_ret)
Widget w;
XEvent * event;
int *ul_ret, *lr_ret;
{
    int xloc, yloc;

    xloc = event->xexpose.x;
    yloc = event->xexpose.y;
    CvtToItem(w, xloc, yloc, ul_ret);
    xloc += event->xexpose.width;
    yloc += event->xexpose.height;
    CvtToItem(w, xloc, yloc, lr_ret);
}

/*	Function Name: ItemInmyRectangle
 *	Description: returns TRUE if the item passed is in the given rectangle.
 *	Arguments: w - the multiList widget.
 *                 ul, lr - corners of the rectangle in item space.
 *                 item - item to check.
 *	Returns: TRUE if the item passed is in the given rectangle.
 */
    
ItemInmyRectangle(w, ul, lr, item)
Widget w;
int ul, lr, item;
{
    MultiListWidget lw = (MultiListWidget) w;
    register int mod_item;
    int things;
    
    if (item < ul || item > lr) 
        return(FALSE);
    if (lw->multiList.vertical_cols)
        things = lw->multiList.nrows;
    else
        things = lw->multiList.ncols;

    mod_item = item % things;
    if ( (mod_item >= ul % things) && (mod_item <= lr % things ) )
        return(TRUE);
    return(FALSE);
}

/*	Function Name: HighlightmyBackground
 *	Description: paints the color of the background for the given item.
 *	Arguments: w - the widget.
 *                 x, y - ul corner of the area item occupies.
 *                 item - the item we are dealing with.
 *                 gc - the gc that is used to paint this rectangle
 *	Returns: 
 */

HighlightmyBackground(w, x, y, item, gc)
Widget w;
int x, y, item;
GC gc;
{
    MultiListWidget lw = (MultiListWidget) w;
    int hl_x, hl_y, width, height;

    hl_x = x - lw->multiList.column_space/2;
    width = XTextWidth(lw->multiList.font, lw->multiList.list[item],
			 strlen(lw->multiList.list[item])) + lw->multiList.column_space;
    hl_y = y - lw->multiList.row_space/2;
    height = lw->multiList.row_height;

    XFillRectangle(XtDisplay(w), XtWindow(w), gc, hl_x, hl_y, width, height);
}

/*	Function Name: PaintmyItemName
 *	Description: paints the name of the item in the appropriate location.
 *	Arguments: w - the multiList widget.
 *                 item - the item to draw.
 *	Returns: none.
 *
 *      NOTE: no action taken on an unrealized widget.
 */

PaintmyItemName(w, item)
Widget w;
int item;
{
    char * str;
    GC gc;
    int x, y, str_y;
    MultiListWidget lw = (MultiListWidget) w;

    if (!XtIsRealized(w)) return; /* Just in case... */
   
    if (lw->multiList.vertical_cols) {
	x = lw->multiList.col_width * (item / lw->multiList.nrows)
	  + lw->multiList.internal_width;
        y = lw->multiList.row_height * (item % lw->multiList.nrows)
	  + lw->multiList.internal_height;
    }
    else {
        x = lw->multiList.col_width * (item % lw->multiList.ncols)
	  + lw->multiList.internal_width;
        y = lw->multiList.row_height * (item / lw->multiList.ncols)
	  + lw->multiList.internal_height;
    }

    str_y = y + lw->multiList.font->max_bounds.ascent;

    if (lw->multiList.single) {
      if (item == lw->multiList.is_highlighted) {
        if (item == lw->multiList.highlight) {
	  gc = lw->multiList.revgc;
	  HighlightmyBackground(w, x, y, item, lw->multiList.normgc);
	}
        else {
	  if (XtIsSensitive(w)) 
	    gc = lw->multiList.normgc;
	  else
	    gc = lw->multiList.graygc;
	  HighlightmyBackground(w, x, y, item, lw->multiList.revgc);
	  lw->multiList.is_highlighted = NO_HIGHLIGHT;
        }
      }
      else {
        if (item == lw->multiList.highlight) {
	  gc = lw->multiList.revgc;
	  HighlightmyBackground(w, x, y, item, lw->multiList.normgc);
	  lw->multiList.is_highlighted = item;
	}
	else {
	  if (XtIsSensitive(w)) 
	    gc = lw->multiList.normgc;
	  else
	    gc = lw->multiList.graygc;
	}
      }
    } else {
      if (lw->multiList.state[item]) {
	gc = lw->multiList.revgc;
	HighlightmyBackground(w, x, y, item, lw->multiList.normgc);
      }
      else {
	if (XtIsSensitive(w)) 
	  gc = lw->multiList.normgc;
	else
	  gc = lw->multiList.graygc;
	HighlightmyBackground(w, x, y, item, lw->multiList.revgc);
      }
    }

    str =  lw->multiList.list[item];	/* draw it */
    XDrawString(XtDisplay(w), XtWindow(w), gc, x, str_y, str, strlen(str));
}
    
/*	Function Name: Redisplay
 *	Description: Repaints the widget window on expose events.
 *	Arguments: w - the multiList widget.
 *                 event - the expose event for this repaint.
 *                 junk - NOT USED.
 *	Returns: 
 */

/* ARGSUSED */
static void 
Redisplay(w, event, junk)
Widget w;
XEvent *event;
Region junk;
{
    int item;			/* an item to work with. */
    int ul_item, lr_item;       /* corners of items we need to paint. */
    MultiListWidget lw = (MultiListWidget) w;

    if (event == NULL) {	/* repaint all. */
        ul_item = 0;
	lr_item = lw->multiList.nrows * lw->multiList.ncols - 1;
	XClearWindow(XtDisplay(w), XtWindow(w));
    }
    else
        FindmyCornerItems(w, event, &ul_item, &lr_item);
    
    for (item = ul_item; (item <= lr_item && item < lw->multiList.nitems) ; item++)
      if (ItemInmyRectangle(w, ul_item, lr_item, item))
	PaintmyItemName(w, item);
}

/*	Function Name: PreferredGeom
 *	Description: This tells the parent what size we would like to be
 *                   given certain constraints.
 *	Arguments: w - the widget.
 *                 intended - what the parent intends to do with us.
 *                 requested - what we want to happen.
 *	Returns: none.
 */

static XtGeometryResult 
PreferredGeom(w, intended, requested)
Widget w;
XtWidgetGeometry *intended, *requested;
{
    Dimension new_width, new_height;
    Boolean change, width_req, height_req;
    
    width_req = intended->request_mode & CWWidth;
    height_req = intended->request_mode & CWHeight;

    if (width_req)
      new_width = intended->width;
    else
      new_width = w->core.width;

    if (height_req)
      new_height = intended->height;
    else
      new_height = w->core.height;

    requested->request_mode = 0;
    
/*
 * We only care about our height and width.
 */

    if ( !width_req && !height_req)
      return(XtGeometryYes);
    
    change = Layout(w, !width_req, !height_req, &new_width, &new_height);

    requested->request_mode |= CWWidth;
    requested->width = new_width;
    requested->request_mode |= CWHeight;
    requested->height = new_height;

    if (change)
        return(XtGeometryAlmost);
    return(XtGeometryYes);
}

/*	Function Name: Resize
 *	Description: resizes the widget, by changing the number of rows and
 *                   columns.
 *	Arguments: w - the widget.
 *	Returns: none.
 */

static void
Resize(w)
Widget w;
{
  Dimension width, height;

  width = w->core.width;
  height = w->core.height;

  if (Layout(w, FALSE, FALSE, &width, &height))
    XtAppWarning(XtWidgetToApplicationContext(w),
	    "MultiList Widget: Size changed when it shouldn't have when resising.");
}

/*	Function Name: Layout
 *	Description: lays out the item in the multiList.
 *	Arguments: w - the widget.
 *                 xfree, yfree - TRUE if we are free to resize the widget in
 *                                this direction.
 *                 width, height - the is the current width and height that 
 *                                 we are going to layout the multiList widget to,
 *                                 depending on xfree and yfree of course.
 *                               
 *	Returns: TRUE if width or height have been changed.
 */

static Boolean
Layout(w, xfree, yfree, width, height)
Widget w;
Boolean xfree, yfree;
Dimension *width, *height;
{
    MultiListWidget lw = (MultiListWidget) w;
    Boolean change = FALSE;
    
/* 
 * If force columns is set then always use number of columns specified
 * by default_cols.
 */

    if (lw->multiList.force_cols) {
        lw->multiList.ncols = lw->multiList.default_cols;
	if (lw->multiList.ncols <= 0) lw->multiList.ncols = 1;
	/* 12/3 = 4 and 10/3 = 4, but 9/3 = 3 */
	lw->multiList.nrows = ( ( lw->multiList.nitems - 1) / lw->multiList.ncols) + 1 ;
	if (xfree) {		/* If allowed resize width. */
	    *width = lw->multiList.ncols * lw->multiList.col_width 
	           + 2 * lw->multiList.internal_width;
	    change = TRUE;
	}
	if (yfree) {		/* If allowed resize height. */
	    *height = (lw->multiList.nrows * lw->multiList.row_height)
                    + 2 * lw->multiList.internal_height;
	    change = TRUE;
	}
	return(change);
    }

/*
 * If both width and height are free to change the use default_cols
 * to determine the number columns and set new width and height to
 * just fit the window.
 */

    if (xfree && yfree) {
        lw->multiList.ncols = lw->multiList.default_cols;
	if (lw->multiList.ncols <= 0) lw->multiList.ncols = 1;
	lw->multiList.nrows = ( ( lw->multiList.nitems - 1) / lw->multiList.ncols) + 1 ;
        *width = lw->multiList.ncols * lw->multiList.col_width
	       + 2 * lw->multiList.internal_width;
	*height = (lw->multiList.nrows * lw->multiList.row_height)
                + 2 * lw->multiList.internal_height;
	change = TRUE;
    }
/* 
 * If the width is fixed then use it to determine the number of columns.
 * If the height is free to move (width still fixed) then resize the height
 * of the widget to fit the current multiList exactly.
 */
    else if (!xfree) {
        lw->multiList.ncols = ( (*width - 2 * lw->multiList.internal_width)
	                    / lw->multiList.col_width);
	if (lw->multiList.ncols <= 0) lw->multiList.ncols = 1;
	lw->multiList.nrows = ( ( lw->multiList.nitems - 1) / lw->multiList.ncols) + 1 ;
	if ( yfree ) {
  	    *height = (lw->multiList.nrows * lw->multiList.row_height)
		    + 2 * lw->multiList.internal_height;
	    change = TRUE;
	}
    }
/* 
 * The last case is xfree and !yfree we use the height to determine
 * the number of rows and then set the width to just fit the resulting
 * number of columns.
 */
    else if (!yfree) {		/* xfree must be TRUE. */
        lw->multiList.nrows = (*height - 2 * lw->multiList.internal_height) 
	               / lw->multiList.row_height;
	if (lw->multiList.nrows <= 0) lw->multiList.nrows = 1;
	lw->multiList.ncols = (( lw->multiList.nitems - 1 ) / lw->multiList.nrows) + 1;
	*width = lw->multiList.ncols * lw->multiList.col_width 
	       + 2 * lw->multiList.internal_width;
	change = TRUE;
    }      
    return(change);
}

/*	Function Name: Notify
 *	Description: Notifies the user that a button has been pressed, and
 *                   calles the callback, if the XtNpasteBuffer resource
 *                   is true then the name of the item is also put in the
 *                   X cut buffer ( buf (0) ).
 *	Arguments: w - the widget that the notify occured in.
 *                 event - event that caused this notification.
 *                 params, num_params - not used.
 *	Returns: none.
 */

/* ARGSUSED */
static void
Notify(w, event, params, num_params)
Widget w;
XEvent * event;
String * params;
Cardinal *num_params;
{
    MultiListWidget lw = ( MultiListWidget ) w;
    int item, item_len;
    XswMultiListReturnStruct ret_value;

/* 
 * Find item and if out of range then unhighlight and return. 
 * 
 * If the current item is unhighlighted then the user has aborted the
 * notify, so unhighlight and return.
 */

    if ( ((CvtToItem(w, event->xbutton.x, event->xbutton.y, &item))
	  == OUT_OF_RANGE)) {
      ret_value.string = "";
      ret_value.list_index = XSW_LIST_NONE;
      XtCallCallbacks( w, XtNcallback, (XPointer) &ret_value);
      return;
    } 
    if (lw->multiList.single && (lw->multiList.highlight != item) ) {
      if (lw->multiList.highlight != NO_HIGHLIGHT)
	XswMultiListUnhighlight(w, lw->multiList.highlight);
      ret_value.string = "";
      ret_value.list_index = XSW_LIST_NONE;
      XtCallCallbacks( w, XtNcallback, (XPointer) &ret_value);
      return;
    }
    

    item_len = strlen(lw->multiList.list[item]);

    if ( lw->multiList.paste )	/* if XtNpasteBuffer set then paste it. */
        XStoreBytes(XtDisplay(w), lw->multiList.list[item], item_len);

/* 
 * Call Callback function.
*/
    if (lw->multiList.single && 
	(lw->multiList.highlight == NO_HIGHLIGHT)) {
      ret_value.string = "";
      ret_value.list_index = XSW_LIST_NONE;
    } else {
      ret_value.string = lw->multiList.list[item];
      ret_value.list_index = item;
    }

    XtCallCallbacks( w, XtNcallback, (XPointer) &ret_value);

}

/*	Function Name: Unset
 *	Description: unhighlights the current element.
 *	Arguments: w - the widget that the event occured in.
 *                 event - not used.
 *                 params, num_params - not used.
 *	Returns: none.
 */

/* ARGSUSED */
static void
Unset(w, event, params, num_params)
Widget w;
XEvent * event;
String * params;
Cardinal *num_params;
{
  int item;

  if ( (CvtToItem(w, event->xbutton.x, event->xbutton.y, &item))
      != OUT_OF_RANGE) {
    XswMultiListUnhighlight(w, item);  /* highlighted then do it. */
  }
}

/*	Function Name: Set
 *	Description: Highlights the current element.
 *	Arguments: w - the widget that the event occured in.
 *                 event - event that caused this notification.
 *                 params, num_params - not used.
 *	Returns: none.
 */

/* ARGSUSED */
static void
Set(w, event, params, num_params)
Widget w;
XEvent * event;
String * params;
Cardinal *num_params;
{
  int item;
  MultiListWidget lw = (MultiListWidget) w;

  if ( (CvtToItem(w, event->xbutton.x, event->xbutton.y, &item))
      != OUT_OF_RANGE) {
    if (lw->multiList.single) { 
      XswMultiListHighlight(w, item);	  
    } else {
      if (!lw->multiList.state[item])
	XswMultiListHighlight(w, item);
      else
	XswMultiListUnhighlight(w, item);	
      lw->multiList.toggle_state = lw->multiList.state[item];
    }
  } else {
    lw->multiList.toggle_state = False;
    for(item = 0; item < lw->multiList.nitems; item++)
      XswMultiListUnhighlight(w, item);	    
  }
}

/* ARGSUSED */
static void
Move(w, event, params, num_params)
Widget w;
XEvent * event;
String * params;
Cardinal *num_params;
{
  int item;
  MultiListWidget lw = (MultiListWidget) w;

  if (!lw->multiList.single) {
    if ( (CvtToItem(w, event->xbutton.x, event->xbutton.y, &item))
	!= OUT_OF_RANGE) {
      
      if (lw->multiList.toggle_state)
	XswMultiListHighlight(w, item);
      else
	XswMultiListUnhighlight(w, item);	
    }
  }
}
/*
 * Set specified arguments into widget
 */
static void
Destroy(cl)
MultiListWidget cl;
{
  XtReleaseGC((Widget) cl, cl->multiList.normgc);
  XtReleaseGC((Widget) cl, cl->multiList.graygc);
  XtReleaseGC((Widget) cl, cl->multiList.revgc);
  XtFree(cl->multiList.state);
}
 

static Boolean 
SetValues(current, request, new)
Widget current, request, new;
{
  int i;
    MultiListWidget cl = (MultiListWidget) current;
    MultiListWidget rl = (MultiListWidget) request;
    MultiListWidget nl = (MultiListWidget) new;
    Boolean redraw = FALSE;

    if ((cl->multiList.foreground != rl->multiList.foreground) ||
	(cl->core.background_pixel != rl->core.background_pixel) ||
	(cl->multiList.font != rl->multiList.font) ) {
        XtReleaseGC((Widget) cl, cl->multiList.normgc);
        XtReleaseGC((Widget) cl, cl->multiList.graygc);
	XtReleaseGC((Widget) cl, cl->multiList.revgc);
        GetGCs(new);
        redraw = TRUE;
    }

    /* Reset row height. */

    if ((cl->multiList.row_space != rl->multiList.row_space) ||
	(cl->multiList.font != rl->multiList.font)) 
        nl->multiList.row_height = nl->multiList.font->max_bounds.ascent
	                    + nl->multiList.font->max_bounds.descent
			    + nl->multiList.row_space;
    
    if ((cl->core.width != rl->core.width)                     ||
	(cl->core.height != rl->core.height)                   ||
	(cl->multiList.internal_width != rl->multiList.internal_width)   ||
	(cl->multiList.internal_height != rl->multiList.internal_height) ||
	(cl->multiList.column_space != rl->multiList.column_space)       ||
	(cl->multiList.row_space != rl->multiList.row_space)             ||
	(cl->multiList.default_cols != rl->multiList.default_cols)       ||
	(  (cl->multiList.force_cols != rl->multiList.force_cols) &&
	   (rl->multiList.force_cols != rl->multiList.ncols) )           ||
	(cl->multiList.vertical_cols != rl->multiList.vertical_cols)     ||
	(cl->multiList.longest != rl->multiList.longest)                 ||
	(cl->multiList.nitems != rl->multiList.nitems)                   ||
	(cl->multiList.font != rl->multiList.font)                       ||
	(cl->multiList.list != rl->multiList.list)                        ) {

      ResetMultiList(new, TRUE, TRUE);
      redraw = TRUE;
    }

    if (cl->multiList.list != rl->multiList.list)
      for(i = 0; i < rl->multiList.nitems; i++)
	cl->multiList.state[i] = False;

    if ((cl->core.sensitive != rl->core.sensitive) ||
	(cl->core.ancestor_sensitive != rl->core.ancestor_sensitive)) {
	redraw = TRUE;
    }
    
    if (!XtIsRealized(current))
      return(FALSE);
      
    return(redraw);
}

/* Exported Functions */

/*	Function Name: XswMultiListChange.
 *	Description: Changes the multiList being used and shown.
 *	Arguments: w - the multiList widget.
 *                 multiList - the new multiList.
 *                 nitems - the number of items in the multiList.
 *                 longest - the length (in Pixels) of the longest element
 *                           in the multiList.
 *                 resize - if TRUE the the multiList widget will
 *                          try to resize itself.
 *	Returns: none.
 *      NOTE:      If nitems of longest are <= 0 then they will be calculated.
 *                 If nitems is <= 0 then the multiList needs to be NULL terminated.
 */

void
XswMultiListChange(w, multiList, nitems, longest, resize_it)
Widget w;
char ** multiList;
int nitems, longest;
Boolean resize_it;
{
    MultiListWidget lw = (MultiListWidget) w;

    lw->multiList.list = multiList;

    if (nitems <= 0) nitems = 0;
    lw->multiList.nitems = nitems;
    if (longest <= 0) longest = 0;
    lw->multiList.longest = longest;

    ResetMultiList(w, resize_it, resize_it);
    if ( XtIsRealized(w) )
      Redisplay(w, NULL, NULL);
}

/*	Function Name: XswMultiListUnhighlight
 *	Description: unlights the current highlighted element.
 *	Arguments: w - the widget.
 *	Returns: none.
 */

void
XswMultiListUnhighlight(w, item)
Widget w;
int item;
{
    MultiListWidget lw = ( MultiListWidget ) w;

    if (lw->multiList.single) {
      lw->multiList.highlight = NO_HIGHLIGHT;
      if (lw->multiList.is_highlighted != NO_HIGHLIGHT)
        PaintmyItemName(w, lw->multiList.is_highlighted);
    } else {
      if (lw->multiList.state[item]) {
	lw->multiList.state[item] = False;
	PaintmyItemName(w, item); /* unhighlight this one. */
      }
    }
}

/*	Function Name: XswMultiListHighlight
 *	Description: Highlights the given item.
 *	Arguments: w - the multiList widget.
 *                 item - the item to hightlight.
 *	Returns: none.
 */

void
XswMultiListHighlight(w, item)
Widget w;
int item;
{
    MultiListWidget lw = ( MultiListWidget ) w;
    
    if (XtIsSensitive(w)) {
      if (lw->multiList.single) {
        lw->multiList.highlight = item;
        if (lw->multiList.is_highlighted != NO_HIGHLIGHT)
	  PaintmyItemName(w, lw->multiList.is_highlighted);
	                                    /* Unhighlight. */
	PaintmyItemName(w, item); /* HIGHLIGHT this one. */ 
      } else {
        if (!lw->multiList.state[item]) {
	  lw->multiList.state[item] = True;
	  PaintmyItemName(w, item); /* HIGHLIGHT this one. */ 
	}
      }
    }
}

/*	Function Name: XswMultiListShowCurrent
 *	Description: returns the currently highlighted object.
 *	Arguments: w - the multiList widget.
 *	Returns: the info about the currently highlighted object.
 */

XswMultiListReturnStruct *
XswMultiListShowCurrent(w)
Widget w;
{
  MultiListWidget lw = ( MultiListWidget ) w;
  XswMultiListReturnStruct * ret_val;
  int i, n;
  ret_val = 
    (XswMultiListReturnStruct *) 
      XtMalloc((lw->multiList.nitems+1) * 
		sizeof(XswMultiListReturnStruct));
  
  if (lw->multiList.single) {
    ret_val->list_index = lw->multiList.highlight;
    if (ret_val->list_index == XSW_LIST_NONE)
      ret_val->string = "";
    else
      ret_val->string = lw->multiList.list[ ret_val->list_index ];
    n = 1;
  } else {
    n = 0;
    for(i = 0; i < lw->multiList.nitems; i++) {
      if (lw->multiList.state[i]) { 
	ret_val[n].string = lw->multiList.list[i];
	ret_val[n].list_index = i;  
	n++;
      }
    }
  }
  ret_val[n].string = "";
  ret_val[n].list_index = XSW_LIST_NONE;
				  
  return(ret_val);
}







These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Marcel Waldvogel and Netfuture.ch.