home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume3 / xsaver / part01 / List.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-03-10  |  27.9 KB  |  981 lines

  1. /*
  2.  * $Source: /mit/sipbsrc/uus/src/xscreensaver/RCS/List.c,v $
  3.  * $Author: jik $
  4.  *
  5.  * This file is part of xscreensaver.  It contains a slightly modified
  6.  * version of the Project Athena list widget which allows the widget
  7.  * to use motion events to set the list, thus allowing the list to act
  8.  * as a menu whose highlighting follows the mouse.
  9.  *
  10.  * Author: Jonathan Kamens, MIT Project Athena and
  11.  *                          MIT Student Information Processing Board
  12.  *         (Well, not really, I just changed a few lines of code.  The
  13.  *          real copyright and stuff is found below.)
  14.  */
  15.  
  16. #if ( !defined(lint) && !defined(SABER))
  17.   static char Xrcs_id[] = "$XConsortium: List.c,v 1.11 88/10/23 14:44:33 swick Exp $";
  18.   static char rcsid_module_c[] = "$oHeader: List.c,v 1.4 88/08/30 16:36:03 kit Exp $";
  19.   static char rcsid_List_c[] = "$Header: List.c,v 1.4 89/02/16 22:53:31 jik Exp $";
  20. #endif
  21.  
  22. /*  This is the List widget, it is useful to display a list, without the
  23.  *  overhead of having a widget for each item in the list.  It allows 
  24.  *  the user to select an item in a list and notifies the application through
  25.  *  a callback function.
  26.  *
  27.  *    Created:     8/13/88
  28.  *    By:        Chris D. Peterson
  29.  *                      MIT - Project Athena
  30.  *
  31.  *      $Author: jik $
  32.  *    
  33.  */
  34.  
  35. /***********************************************************
  36. Copyright 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
  37. and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
  38.  
  39.                         All Rights Reserved
  40.  
  41. Permission to use, copy, modify, and distribute this software and its 
  42. documentation for any purpose and without fee is hereby granted, 
  43. provided that the above copyright notice appear in all copies and that
  44. both that copyright notice and this permission notice appear in 
  45. supporting documentation, and that the names of Digital or MIT not be
  46. used in advertising or publicity pertaining to distribution of the
  47. software without specific, written prior permission.  
  48.  
  49. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  50. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  51. DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  52. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  53. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  54. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  55. SOFTWARE.
  56.  
  57. ******************************************************************/
  58.  
  59. /*
  60.  * List.c - List widget
  61.  *
  62.  */
  63.  
  64. #include <X11/IntrinsicP.h>
  65. #include <stdio.h>
  66. #include <X11/Xos.h>
  67. #include <ctype.h>
  68. #include <X11/StringDefs.h>
  69. #include <X11/ListP.h>
  70.  
  71. char * malloc();
  72.  
  73. /* 
  74.  * Default Translation table.
  75.  */
  76.  
  77. static char defaultTranslations[] =  
  78.   "<Btn1Down>:   Set()\n\
  79.    <Btn1Up>:     Notify()";
  80.  
  81. /****************************************************************
  82.  *
  83.  * Full class record constant
  84.  *
  85.  ****************************************************************/
  86.  
  87. /* Private Data */
  88.  
  89. #define offset(field) XtOffset(ListWidget, field)
  90.  
  91. static XtResource resources[] = {
  92.     {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
  93.     offset(list.foreground), XtRString, "XtDefaultForeground"},
  94.     {XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor),
  95.        offset(simple.cursor), XtRString, "left_ptr"},
  96.     {XtNfont,  XtCFont, XtRFontStruct, sizeof(XFontStruct *),
  97.     offset(list.font),XtRString, "XtDefaultFont"},
  98.     {XtNlist, XtCList, XtRPointer, sizeof(char **),
  99.        offset(list.list), XtRString, NULL},
  100.     {XtNdefaultColumns, XtCColumns, XtRInt,  sizeof(int),
  101.     offset(list.default_cols), XtRImmediate, (caddr_t)2},
  102.     {XtNlongest, XtCLongest, XtRInt,  sizeof(int),
  103.     offset(list.longest), XtRImmediate, (caddr_t)0},
  104.     {XtNnumberStrings, XtCNumberStrings, XtRInt,  sizeof(int),
  105.     offset(list.nitems), XtRImmediate, (caddr_t)0},
  106.     {XtNpasteBuffer, XtCBoolean, XtRBoolean,  sizeof(Boolean),
  107.     offset(list.paste), XtRString, (caddr_t) "False"},
  108.     {XtNforceColumns, XtCColumns, XtRBoolean,  sizeof(Boolean),
  109.     offset(list.force_cols), XtRString, (caddr_t) "False"},
  110.     {XtNverticalList, XtCBoolean, XtRBoolean,  sizeof(Boolean),
  111.     offset(list.vertical_cols), XtRString, (caddr_t) "False"},
  112.     {XtNinternalWidth, XtCWidth, XtRDimension,  sizeof(Dimension),
  113.     offset(list.internal_width), XtRImmediate, (caddr_t)4},
  114.     {XtNinternalHeight, XtCHeight, XtRDimension, sizeof(Dimension),
  115.     offset(list.internal_height), XtRImmediate, (caddr_t)2},
  116.     {XtNcolumnSpacing, XtCSpacing, XtRDimension,  sizeof(Dimension),
  117.     offset(list.column_space), XtRImmediate, (caddr_t)6},
  118.     {XtNrowSpacing, XtCSpacing, XtRDimension,  sizeof(Dimension),
  119.     offset(list.row_space), XtRImmediate, (caddr_t)2},
  120.     {XtNcallback, XtCCallback, XtRCallback, sizeof(caddr_t),
  121.         offset(list.callback), XtRCallback, NULL},
  122. };
  123.  
  124. static void Initialize();
  125. static void ChangeSize();
  126. static void Resize();
  127. static void Redisplay();
  128. static Boolean Layout();
  129. static XtGeometryResult PreferredGeom();
  130. static Boolean SetValues();
  131. static void Notify(), Set(), Unset();
  132. static int old_highlighted_item = -1;
  133.  
  134. static XtActionsRec actions[] = {
  135.       {"Notify",         Notify},
  136.       {"Set",            Set},
  137.       {"Unset",          Unset},
  138.       {NULL,NULL}
  139. };
  140.  
  141. ListClassRec listClassRec = {
  142.   {
  143. /* core_class fields */    
  144. #define superclass        (&simpleClassRec)
  145.     /* superclass          */    (WidgetClass) superclass,
  146.     /* class_name          */    "List",
  147.     /* widget_size          */    sizeof(ListRec),
  148.     /* class_initialize       */    NULL,
  149.     /* class_part_initialize    */    NULL,
  150.     /* class_inited           */    FALSE,
  151.     /* initialize          */    Initialize,
  152.     /* initialize_hook        */    NULL,
  153.     /* realize              */    XtInheritRealize,
  154.     /* actions              */    actions,
  155.     /* num_actions          */    XtNumber(actions),
  156.     /* resources          */    resources,
  157.     /* num_resources          */    XtNumber(resources),
  158.     /* xrm_class          */    NULLQUARK,
  159.     /* compress_motion          */    FALSE,
  160.     /* compress_exposure      */    FALSE,
  161.     /* compress_enterleave    */    TRUE,
  162.     /* visible_interest          */    FALSE,
  163.     /* destroy              */    NULL,
  164.     /* resize              */    Resize,
  165.     /* expose              */    Redisplay,
  166.     /* set_values          */    SetValues,
  167.     /* set_values_hook        */    NULL,
  168.     /* set_values_almost    */    XtInheritSetValuesAlmost,
  169.     /* get_values_hook        */    NULL,
  170.     /* accept_focus         */    NULL,
  171.     /* version            */    XtVersion,
  172.     /* callback_private       */    NULL,
  173.     /* tm_table               */    defaultTranslations,
  174.    /* query_geometry        */      PreferredGeom,
  175.   }
  176. };
  177.  
  178. WidgetClass listWidgetClass = (WidgetClass)&listClassRec;
  179.  
  180. /****************************************************************
  181.  *
  182.  * Private Procedures
  183.  *
  184.  ****************************************************************/
  185.  
  186. static void GetGCs(w)
  187. Widget w;
  188. {
  189.     XGCValues    values;
  190.     ListWidget lw = (ListWidget) w;    
  191.  
  192.     values.foreground    = lw->list.foreground;
  193.     values.font        = lw->list.font->fid;
  194.  
  195.     lw->list.normgc = XtGetGC(w, (unsigned) GCForeground | GCFont,
  196.                  &values);
  197.  
  198.     values.foreground    = lw->core.background_pixel;
  199.  
  200.     lw->list.revgc = XtGetGC(w, (unsigned) GCForeground | GCFont,
  201.                  &values);
  202.  
  203.     values.foreground = lw->list.foreground;
  204.     values.tile       = XtGrayPixmap(XtScreen(w));
  205.     values.fill_style = FillTiled;
  206.  
  207.     lw->list.graygc = XtGetGC(w, (unsigned) GCForeground | GCFont |
  208.                   GCTile | GCFillStyle, &values);
  209. }
  210.  
  211. /*    Function Name: ResetList
  212.  *    Description: Resets the new list when important things change.
  213.  *    Arguments: w - the widget.
  214.  *                 changex, changey - allow the height or width to change?
  215.  *    Returns: none.
  216.  */
  217.  
  218. static void
  219. ResetList(w, changex, changey)
  220. Widget w;
  221. Boolean changex, changey;
  222. {
  223.     ListWidget lw = (ListWidget) w;
  224.     int width = w->core.width;
  225.     int height = w->core.height;
  226.  
  227.     if (lw->list.nitems == 0)    /* Get number of items. */
  228.         while (lw->list.list[lw->list.nitems] != NULL)
  229.         lw->list.nitems++;
  230.  
  231.     if (lw->list.longest == 0) { /* Get column width. */
  232.         int i, len, max;
  233.         for ( i = 0, max = 0; i < lw->list.nitems; i++) {
  234.         len = XTextWidth(lw->list.font, lw->list.list[i],
  235.                  strlen(lw->list.list[i]));
  236.         if (len > max)
  237.             max = len;
  238.     }
  239.         lw->list.col_width = max;
  240.     }
  241.     else 
  242.         lw->list.col_width = lw->list.longest;
  243.     lw->list.col_width += lw->list.column_space;
  244.  
  245.     if (Layout(w, changex, changey, &width, &height))
  246.       ChangeSize(w, width, height);
  247. }
  248.  
  249. /*    Function Name: ChangeSize.
  250.  *    Description: Laysout the widget.
  251.  *    Arguments: w - the widget to try change the size of.
  252.  *    Returns: none.
  253.  */
  254.  
  255. static void
  256. ChangeSize(w, width, height)
  257. Widget w;
  258. int width, height;
  259. {
  260.     int w_ret, h_ret;
  261.  
  262.     (void) Layout(w, FALSE, FALSE, &width, &height);
  263.  
  264.     switch ( XtMakeResizeRequest(w, width, height, &w_ret, &h_ret) ) {
  265.     case XtGeometryYes:
  266.     case XtGeometryNo:
  267.         break;
  268.     case XtGeometryAlmost:
  269.         if (Layout(w, FALSE, FALSE, &width, &height)) {
  270.             XtWarning("Size Changed when it shouldn't have...");
  271.         XtWarning("when initializing the List Widget");
  272.     }
  273.     (void) XtMakeResizeRequest(w, w_ret, h_ret, NULL, NULL);
  274.     break;
  275.     default:
  276.     XtWarning("Unknown geometry return in List Widget");
  277.     break;
  278.     }
  279. }
  280.  
  281. /*    Function Name: Initialize
  282.  *    Description: Function that initilizes the widget instance.
  283.  *    Arguments: junk - NOT USED.
  284.  *                 new  - the new widget.
  285.  *    Returns: none
  286.  */
  287.  
  288. /* ARGSUSED */
  289. static void 
  290. Initialize(junk, new)
  291. Widget junk, new;
  292. {
  293.     ListWidget lw = (ListWidget) new;
  294.  
  295. /* 
  296.  * Initialize all private resources.
  297.  */
  298.  
  299.     GetGCs(new);
  300.  
  301.     /* Set row height. */
  302.     lw->list.row_height = lw->list.font->max_bounds.ascent
  303.             + lw->list.font->max_bounds.descent
  304.             + lw->list.row_space;
  305.  
  306.     ResetList(new, (new->core.width == 0), (new->core.height == 0));
  307.  
  308. /*
  309.  * Default to the name of the widget as the entire list.
  310.  */
  311.  
  312.     if (lw->list.list == NULL) {
  313.       lw->list.list = &(lw->core.name);
  314.       lw->list.nitems = 1;
  315.     }
  316.  
  317.     lw->list.is_highlighted = NO_HIGHLIGHT;
  318.     lw->list.highlight = NO_HIGHLIGHT;
  319.  
  320. } /* Initialize */
  321.  
  322. /*    Function Name: CvtToItem
  323.  *    Description: Converts Xcoord to item number of item containing that
  324.  *                   point.
  325.  *    Arguments: w - the list widget.
  326.  *                 xloc, yloc - x location, and y location.
  327.  *    Returns: the item number.
  328.  */
  329.  
  330. static int
  331. CvtToItem(w, xloc, yloc, item)
  332. Widget w;
  333. int xloc, yloc;
  334. int *item;
  335. {
  336.     int one, another;
  337.     ListWidget lw = (ListWidget) w;
  338.     int ret_val = OKAY;
  339.  
  340.     if (lw->list.vertical_cols) {
  341.         one = lw->list.nrows * ((xloc - (int) lw->list.internal_width)
  342.         / lw->list.col_width);
  343.         another = (yloc - (int) lw->list.internal_height) 
  344.             / lw->list.row_height;
  345.      /* If out of range, return minimum possible value. */
  346.     if (another >= lw->list.nrows) {
  347.         another = lw->list.nrows - 1;
  348.         ret_val = OUT_OF_RANGE;
  349.     }
  350.     }
  351.     else {
  352.         one = (lw->list.ncols * ((yloc - (int) lw->list.internal_height) 
  353.               / lw->list.row_height)) ;
  354.     /* If in right margin handle things right. */
  355.         another = (xloc - (int) lw->list.internal_width) / lw->list.col_width;
  356.     if (another >= lw->list.ncols) {
  357.         another = lw->list.ncols - 1; 
  358.         ret_val = OUT_OF_RANGE;
  359.     }
  360.     }  
  361.     if ((xloc < 0) || (yloc < 0))
  362.         ret_val = OUT_OF_RANGE;
  363.     if (one < 0) one = 0;
  364.     if (another < 0) another = 0;
  365.     *item = one + another;
  366.     if (*item >= lw->list.nitems) return(OUT_OF_RANGE);
  367.     return(ret_val);
  368. }
  369.  
  370. /*    Function Name: FindCornerItems.
  371.  *    Description: Find the corners of the rectangle in item space.
  372.  *    Arguments: w - the list widget.
  373.  *                 event - the event structure that has the rectangle it it.
  374.  *                 ul_ret, lr_ret - the corners ** RETURNED **.
  375.  *    Returns: none.
  376.  */
  377.  
  378. FindCornerItems(w, event, ul_ret, lr_ret)
  379. Widget w;
  380. XEvent * event;
  381. int *ul_ret, *lr_ret;
  382. {
  383.     int xloc, yloc;
  384.  
  385.     xloc = event->xexpose.x;
  386.     yloc = event->xexpose.y;
  387.     CvtToItem(w, xloc, yloc, ul_ret);
  388.     xloc += event->xexpose.width;
  389.     yloc += event->xexpose.height;
  390.     CvtToItem(w, xloc, yloc, lr_ret);
  391. }
  392.  
  393. /*    Function Name: ItemInRectangle
  394.  *    Description: returns TRUE if the item passed is in the given rectangle.
  395.  *    Arguments: w - the list widget.
  396.  *                 ul, lr - corners of the rectangle in item space.
  397.  *                 item - item to check.
  398.  *    Returns: TRUE if the item passed is in the given rectangle.
  399.  */
  400.     
  401. ItemInRectangle(w, ul, lr, item)
  402. Widget w;
  403. int ul, lr, item;
  404. {
  405.     ListWidget lw = (ListWidget) w;
  406.     register int mod_item;
  407.     int things;
  408.     
  409.     if (item < ul || item > lr) 
  410.         return(FALSE);
  411.     if (lw->list.vertical_cols)
  412.         things = lw->list.nrows;
  413.     else
  414.         things = lw->list.ncols;
  415.  
  416.     mod_item = item % things;
  417.     if ( (mod_item >= ul % things) && (mod_item <= lr % things ) )
  418.         return(TRUE);
  419.     return(FALSE);
  420. }
  421.  
  422. /*    Function Name: HighlightBackground
  423.  *    Description: paints the color of the background for the given item.
  424.  *    Arguments: w - the widget.
  425.  *                 x, y - ul corner of the area item occupies.
  426.  *                 item - the item we are dealing with.
  427.  *                 gc - the gc that is used to paint this rectangle
  428.  *    Returns: 
  429.  */
  430.  
  431. HighlightBackground(w, x, y, item, gc)
  432. Widget w;
  433. int x, y, item;
  434. GC gc;
  435. {
  436.     ListWidget lw = (ListWidget) w;
  437.     int hl_x, hl_y, width, height;
  438.  
  439.     hl_x = x - lw->list.column_space/2;
  440.     width =lw->list.col_width + lw->list.column_space;
  441.     hl_y = y - lw->list.row_space/2;
  442.     height = lw->list.row_height + lw->list.row_space;
  443.  
  444.     XFillRectangle(XtDisplay(w), XtWindow(w), gc, hl_x, hl_y, width, height);
  445. }
  446.  
  447. /*    Function Name: PaintItemName
  448.  *    Description: paints the name of the item in the appropriate location.
  449.  *    Arguments: w - the list widget.
  450.  *                 item - the item to draw.
  451.  *    Returns: none.
  452.  */
  453.  
  454. PaintItemName(w, item)
  455. Widget w;
  456. int item;
  457. {
  458.     char * str;
  459.     GC gc;
  460.     int x, y, str_y;
  461.     ListWidget lw = (ListWidget) w;
  462.    
  463.     if (lw->list.vertical_cols) {
  464.     x = lw->list.col_width * (item / lw->list.nrows)
  465.       + lw->list.internal_width;
  466.         y = lw->list.row_height * (item % lw->list.nrows)
  467.       + lw->list.internal_height;
  468.     }
  469.     else {
  470.         x = lw->list.col_width * (item % lw->list.ncols)
  471.       + lw->list.internal_width;
  472.         y = lw->list.row_height * (item / lw->list.ncols)
  473.       + lw->list.internal_height;
  474.     }
  475.  
  476.     str_y = y + lw->list.font->max_bounds.ascent;
  477.  
  478.     if (item == lw->list.is_highlighted) {
  479.         if (item == lw->list.highlight) {
  480.             gc = lw->list.revgc;
  481.         HighlightBackground(w, x, y, item, lw->list.normgc);
  482.     }
  483.         else {
  484.         if (XtIsSensitive(w)) 
  485.             gc = lw->list.normgc;
  486.         else
  487.             gc = lw->list.graygc;
  488.         HighlightBackground(w, x, y, item, lw->list.revgc);
  489.         lw->list.is_highlighted = NO_HIGHLIGHT;
  490.         }
  491.     }
  492.     else {
  493.         if (item == lw->list.highlight) {
  494.             gc = lw->list.revgc;
  495.         HighlightBackground(w, x, y, item, lw->list.normgc);
  496.         lw->list.is_highlighted = item;
  497.     }
  498.     else {
  499.         if (XtIsSensitive(w)) 
  500.             gc = lw->list.normgc;
  501.         else
  502.             gc = lw->list.graygc;
  503.     }
  504.     }
  505.  
  506.     str =  lw->list.list[item];    /* draw it */
  507.     XDrawString(XtDisplay(w), XtWindow(w), gc, x, str_y, str, strlen(str));
  508. }
  509.     
  510. /*    Function Name: Redisplay
  511.  *    Description: Repaints the widget window on expose events.
  512.  *    Arguments: w - the list widget.
  513.  *                 event - the expose event for this repaint.
  514.  *                 junk - NOT USED.
  515.  *    Returns: 
  516.  */
  517.  
  518. /* ARGSUSED */
  519. static void 
  520. Redisplay(w, event, junk)
  521. Widget w;
  522. XEvent *event;
  523. Region junk;
  524. {
  525.     int item;            /* an item to work with. */
  526.     int ul_item, lr_item;       /* corners of items we need to paint. */
  527.     ListWidget lw = (ListWidget) w;
  528.  
  529.     if (event == NULL) {    /* repaint all. */
  530.         ul_item = 0;
  531.     lr_item = lw->list.nrows * lw->list.ncols - 1;
  532.     XClearWindow(XtDisplay(w), XtWindow(w));
  533.     }
  534.     else
  535.         FindCornerItems(w, event, &ul_item, &lr_item);
  536.     
  537.     for (item = ul_item; (item <= lr_item && item < lw->list.nitems) ; item++)
  538.       if (ItemInRectangle(w, ul_item, lr_item, item))
  539.     PaintItemName(w, item);
  540. }
  541.  
  542. /*    Function Name: PreferredGeom
  543.  *    Description: This tells the parent what size we would like to be
  544.  *                   given certain constraints.
  545.  *    Arguments: w - the widget.
  546.  *                 intended - what the parent intends to do with us.
  547.  *                 requested - what we want to happen.
  548.  *    Returns: none.
  549.  */
  550.  
  551. static XtGeometryResult 
  552. PreferredGeom(w, intended, requested)
  553. Widget w;
  554. XtWidgetGeometry *intended, *requested;
  555. {
  556.     int width_req, height_req, new_width, new_height;
  557.     Boolean change;
  558.     
  559.     width_req = intended->request_mode & CWWidth;
  560.     height_req = intended->request_mode & CWHeight;
  561.     if (width_req)
  562.       new_width = intended->width;
  563.     else
  564.       new_width = w->core.width;
  565.  
  566.     if (height_req)
  567.       new_height = intended->height;
  568.     else
  569.       new_height = w->core.height;
  570.  
  571.     requested->request_mode = 0;
  572.     
  573. /*
  574.  * We only care about our height and width.
  575.  */
  576.  
  577.     if ( !width_req && !height_req) {
  578.       return(XtGeometryYes);
  579.     }
  580.     
  581.     change = Layout(w, !width_req, !height_req, &new_width, &new_height);
  582.  
  583.     requested->request_mode |= CWWidth;
  584.     requested->width = new_width;
  585.     requested->request_mode |= CWHeight;
  586.     requested->height = new_height;
  587.  
  588.     if (change)
  589.         return(XtGeometryAlmost);
  590.     return(XtGeometryYes);
  591. }
  592.  
  593. /*    Function Name: Resize
  594.  *    Description: resizes the widget, by changing the number of rows and
  595.  *                   columns.
  596.  *    Arguments: w - the widget.
  597.  *    Returns: none.
  598.  */
  599.  
  600. static void
  601. Resize(w)
  602. Widget w;
  603. {
  604.   int width, height;
  605.  
  606.   width = w->core.width;
  607.   height = w->core.height;
  608.  
  609.   if (Layout(w, FALSE, FALSE, &width, &height))
  610.     XtWarning(
  611.       "Size Changed when it shouldn't have in Resizing the List Widget");
  612. }
  613.  
  614. /*    Function Name: Layout
  615.  *    Description: lays out the item in the list.
  616.  *    Arguments: w - the widget.
  617.  *                 xfree, yfree - TRUE if we are free to resize the widget in
  618.  *                                this direction.
  619.  *                 width, height - the is the current width and height that 
  620.  *                                 we are going to layout the list widget to,
  621.  *                                 depending on xfree and yfree of course.
  622.  *                               
  623.  *    Returns: TRUE if width or height have been changed.
  624.  */
  625.  
  626. static Boolean
  627. Layout(w, xfree, yfree, width, height)
  628. Widget w;
  629. Boolean xfree, yfree;
  630. int *width, *height;
  631. {
  632.     ListWidget lw = (ListWidget) w;
  633.     Boolean change = FALSE;
  634.     
  635. /* 
  636.  * If force columns is set then always use number of columns specified
  637.  * by default_cols.
  638.  */
  639.  
  640.     if (lw->list.force_cols) {
  641.         lw->list.ncols = lw->list.default_cols;
  642.     if (lw->list.ncols <= 0) lw->list.ncols = 1;
  643.     /* 12/3 = 4 and 10/3 = 4, but 9/3 = 3 */
  644.     lw->list.nrows = ( ( lw->list.nitems - 1) / lw->list.ncols) + 1 ;
  645.     if (xfree) {        /* If allowed resize width. */
  646.         *width = lw->list.ncols * lw->list.col_width 
  647.                + 2 * lw->list.internal_width;
  648.         change = TRUE;
  649.     }
  650.     if (yfree) {        /* If allowed resize height. */
  651.         *height = (lw->list.nrows * lw->list.row_height)
  652.                     + 2 * lw->list.internal_height;
  653.         change = TRUE;
  654.     }
  655.     return(change);
  656.     }
  657.  
  658. /*
  659.  * If both width and height are free to change the use default_cols
  660.  * to determine the number columns and set new width and height to
  661.  * just fit the window.
  662.  */
  663.  
  664.     if (xfree && yfree) {
  665.         lw->list.ncols = lw->list.default_cols;
  666.     if (lw->list.ncols <= 0) lw->list.ncols = 1;
  667.     lw->list.nrows = ( ( lw->list.nitems - 1) / lw->list.ncols) + 1 ;
  668.         *width = lw->list.ncols * lw->list.col_width
  669.            + 2 * lw->list.internal_width;
  670.     *height = (lw->list.nrows * lw->list.row_height)
  671.                 + 2 * lw->list.internal_height;
  672.     change = TRUE;
  673.     }
  674. /* 
  675.  * If the width is fixed then use it to determine the number of columns.
  676.  * If the height is free to move (width still fixed) then resize the height
  677.  * of the widget to fit the current list exactly.
  678.  */
  679.     else if (!xfree) {
  680.         lw->list.ncols = (*width - 2 * lw->list.internal_width)
  681.                    / lw->list.col_width;
  682.     if (lw->list.ncols <= 0) lw->list.ncols = 1;
  683.     lw->list.nrows = ( ( lw->list.nitems - 1) / lw->list.ncols) + 1 ;
  684.     if ( yfree ) {
  685.           *height = (lw->list.nrows * lw->list.row_height)
  686.             + 2 * lw->list.internal_height;
  687.         change = TRUE;
  688.     }
  689.     }
  690. /* 
  691.  * The last case is xfree and !yfree we use the height to determine
  692.  * the number of rows and then set the width to just fit the resulting
  693.  * number of columns.
  694.  */
  695.     else if (!yfree) {        /* xfree must be TRUE. */
  696.         lw->list.nrows = (*height - 2 * lw->list.internal_height) 
  697.                    / lw->list.row_height;
  698.     if (lw->list.nrows <= 0) lw->list.nrows = 1;
  699.     lw->list.ncols = (( lw->list.nitems - 1 ) / lw->list.nrows) + 1;
  700.     *width = lw->list.ncols * lw->list.col_width 
  701.            + 2 * lw->list.internal_width;
  702.     change = TRUE;
  703.     }      
  704.     return(change);
  705. }
  706.  
  707. /*    Function Name: Notify
  708.  *    Description: Notifies the user that a button has been pressed, and
  709.  *                   calles the callback, if the XtNpasteBuffer resource
  710.  *                   is true then the name of the item is also put in the
  711.  *                   X cut buffer ( buf (0) ).
  712.  *    Arguments: w - the widget that the notify occured in.
  713.  *                 event - event that caused this notification.
  714.  *                 params, num_params - not used.
  715.  *    Returns: none.
  716.  */
  717.  
  718. /* ARGSUSED */
  719. static void
  720. Notify(w, event, params, num_params)
  721. Widget w;
  722. XEvent * event;
  723. String * params;
  724. Cardinal *num_params;
  725. {
  726.     ListWidget lw = ( ListWidget ) w;
  727.     int item, item_len;
  728.     XtListReturnStruct ret_value;
  729.  
  730. /* 
  731.  * Find item and if out of range then unhighlight and return. 
  732.  * 
  733.  * If the current item is unhighlighted then the user has aborted the
  734.  * notify, so unhighlight and return.
  735.  */
  736.  
  737.     if ( ((CvtToItem(w, event->xbutton.x, event->xbutton.y, &item))
  738.       == OUT_OF_RANGE) || (lw->list.highlight != item) ) {
  739.         XtListUnhighlight(w);
  740.         return;
  741.     }
  742.  
  743.     item_len = strlen(lw->list.list[item]);
  744.  
  745.     if ( lw->list.paste )    /* if XtNpasteBuffer set then paste it. */
  746.         XStoreBytes(XtDisplay(w), lw->list.list[item], item_len);
  747.  
  748. /* 
  749.  * Call Callback function.
  750.  */
  751.  
  752.     ret_value.string = lw->list.list[item];
  753.     ret_value.index = item;
  754.     
  755.     XtCallCallbacks( w, XtNcallback, (caddr_t) &ret_value);
  756. }
  757.  
  758. /*    Function Name: Unset
  759.  *    Description: unhighlights the current element.
  760.  *    Arguments: w - the widget that the event occured in.
  761.  *                 event - not used.
  762.  *                 params, num_params - not used.
  763.  *    Returns: none.
  764.  */
  765.  
  766. /* ARGSUSED */
  767. static void
  768. Unset(w, event, params, num_params)
  769. Widget w;
  770. XEvent * event;
  771. String * params;
  772. Cardinal *num_params;
  773. {
  774.   old_highlighted_item = -1;  
  775.   XtListUnhighlight(w);
  776. }
  777.  
  778. /*    Function Name: Set
  779.  *    Description: Highlights the current element.
  780.  *    Arguments: w - the widget that the event occured in.
  781.  *                 event - event that caused this notification.
  782.  *                 params, num_params - not used.
  783.  *    Returns: none.
  784.  */
  785.  
  786. /* ARGSUSED */
  787. static void
  788. Set(w, event, params, num_params)
  789. Widget w;
  790. XEvent * event;
  791. String * params;
  792. Cardinal *num_params;
  793. {
  794.   int item;
  795.   ListWidget lw = (ListWidget) w;
  796.   
  797. /* Find item and if out of range then return. */
  798.  
  799.   if ( (CvtToItem(w, event->xbutton.x, event->xbutton.y, &item))
  800.       == OUT_OF_RANGE)
  801.        return;
  802.   
  803.   if ((old_highlighted_item != item) ||
  804.       (lw->list.is_highlighted == NO_HIGHLIGHT)) {
  805.        
  806.     XtListUnhighlight(w);        /* Unhighlight current item. */
  807.  
  808.     XtListHighlight(w, item);    /* Highlight new item. */
  809.     old_highlighted_item = item;
  810.   }
  811. }
  812.  
  813. /*
  814.  * Set specified arguments into widget
  815.  */
  816.  
  817. /* ARGSUSED */
  818. static Boolean SetValues(current, request, new)
  819. Widget current, request, new;
  820. {
  821.     ListWidget cl = (ListWidget) current;
  822.     ListWidget rl = (ListWidget) request;
  823.     ListWidget nl = (ListWidget) new;
  824.     Boolean redraw = FALSE;
  825.  
  826.     if ((cl->list.foreground != rl->list.foreground) ||
  827.     (cl->core.background_pixel != rl->core.background_pixel) ||
  828.     (cl->list.font != rl->list.font) ) {
  829.         XtDestroyGC(cl->list.normgc);
  830.         XtDestroyGC(cl->list.graygc);
  831.     XtDestroyGC(cl->list.revgc);
  832.         GetGCs(new);
  833.         redraw = TRUE;
  834.     }
  835.  
  836.     /* Reset row height. */
  837.  
  838.     if ((cl->list.row_space != rl->list.row_space) ||
  839.     (cl->list.font != rl->list.font)) 
  840.         nl->list.row_height = nl->list.font->max_bounds.ascent
  841.                         + nl->list.font->max_bounds.descent
  842.                 + nl->list.row_space;
  843.     
  844.     if ((cl->core.width != rl->core.width)                     ||
  845.     (cl->core.height != rl->core.height)                   ||
  846.     (cl->list.internal_width != rl->list.internal_width)   ||
  847.     (cl->list.internal_height != rl->list.internal_height) ||
  848.     (cl->list.column_space != rl->list.column_space)       ||
  849.     (cl->list.row_space != rl->list.row_space)             ||
  850.     (cl->list.default_cols != rl->list.default_cols)       ||
  851.     (  (cl->list.force_cols != rl->list.force_cols) &&
  852.        (rl->list.force_cols != rl->list.ncols) )           ||
  853.     (cl->list.vertical_cols != rl->list.vertical_cols)     ||
  854.     (cl->list.longest != rl->list.longest)                 ||
  855.     (cl->list.nitems != rl->list.nitems)                   ||
  856.     (cl->list.font != rl->list.font)                       ||
  857.     (cl->list.list != rl->list.list)                        ) {
  858.  
  859.       ResetList(new, TRUE, TRUE);
  860.       redraw = TRUE;
  861.     }
  862.  
  863.     if (cl->list.list != rl->list.list)
  864.       nl->list.highlight = NO_HIGHLIGHT;
  865.  
  866.     if ((cl->core.sensitive != rl->core.sensitive) ||
  867.     (cl->core.ancestor_sensitive != rl->core.ancestor_sensitive)) {
  868.         nl->list.highlight = NO_HIGHLIGHT;
  869.     redraw = TRUE;
  870.     }
  871.     
  872.     if (!XtIsRealized(current))
  873.       return(FALSE);
  874.       
  875.     return(redraw);
  876. }
  877.  
  878. /* Exported Functions */
  879.  
  880. /*    Function Name: XtListChange.
  881.  *    Description: Changes the list being used and shown.
  882.  *    Arguments: w - the list widget.
  883.  *                 list - the new list.
  884.  *                 nitems - the number of items in the list.
  885.  *                 longest - the length (in Pixels) of the longest element
  886.  *                           in the list.
  887.  *                 resize - if TRUE the the list widget will
  888.  *                          try to resize itself.
  889.  *    Returns: none.
  890.  *      NOTE:      If nitems of longest are <= 0 then they will be calculated.
  891.  *                 If nitems is <= 0 then the list needs to be NULL terminated.
  892.  */
  893.  
  894. void
  895. XtListChange(w, list, nitems, longest, resize_it)
  896. Widget w;
  897. char ** list;
  898. int nitems, longest;
  899. Boolean resize_it;
  900. {
  901.     ListWidget lw = (ListWidget) w;
  902.  
  903.     lw->list.list = list;
  904.  
  905.     if (nitems <= 0) nitems = 0;
  906.     lw->list.nitems = nitems;
  907.     if (longest <= 0) longest = 0;
  908.     lw->list.longest = longest;
  909.  
  910.     ResetList(w, resize_it, resize_it);
  911.     lw->list.highlight = NO_HIGHLIGHT;
  912.     if ( XtIsRealized(w) )
  913.       Redisplay(w, NULL, NULL);
  914. }
  915.  
  916. /*    Function Name: XtListUnhighlight
  917.  *    Description: unlights the current highlighted element.
  918.  *    Arguments: w - the widget.
  919.  *    Returns: none.
  920.  */
  921.  
  922. void
  923. XtListUnhighlight(w)
  924. Widget w;
  925. {
  926.     ListWidget lw = ( ListWidget ) w;
  927.  
  928.     lw->list.highlight = NO_HIGHLIGHT;
  929.     if (lw->list.is_highlighted != NO_HIGHLIGHT)
  930.         PaintItemName(w, lw->list.is_highlighted); /* unhighlight this one. */
  931. }
  932.  
  933. /*    Function Name: XtListHighlight
  934.  *    Description: Highlights the given item.
  935.  *    Arguments: w - the list widget.
  936.  *                 item - the item to hightlight.
  937.  *    Returns: none.
  938.  */
  939.  
  940. void
  941. XtListHighlight(w, item)
  942. Widget w;
  943. int item;
  944. {
  945.     ListWidget lw = ( ListWidget ) w;
  946.     
  947.     if (XtIsSensitive(w)) {
  948.         lw->list.highlight = item;
  949.         if (lw->list.is_highlighted != NO_HIGHLIGHT)
  950.             PaintItemName(w, lw->list.is_highlighted);  /* Unhighlight. */
  951.     PaintItemName(w, item); /* HIGHLIGHT this one. */ 
  952.     }
  953. }
  954.  
  955. /*    Function Name: XtListShowCurrent
  956.  *    Description: returns the currently highlighted object.
  957.  *    Arguments: w - the list widget.
  958.  *    Returns: the info about the currently highlighted object.
  959.  */
  960.  
  961. XtListReturnStruct *
  962. XtListShowCurrent(w)
  963. Widget w;
  964. {
  965.     ListWidget lw = ( ListWidget ) w;
  966.     XtListReturnStruct * ret_val;
  967.  
  968.     ret_val = (XtListReturnStruct *) malloc (sizeof (XtListReturnStruct));
  969.     if (ret_val == NULL)
  970.       XtError("Could not allocate memory in XtListShowCurrent.");
  971.     
  972.     ret_val->index = lw->list.highlight;
  973.     if (ret_val->index == XT_LIST_NONE)
  974.       ret_val->string = "";
  975.     else
  976.       ret_val->string = lw->list.list[ ret_val->index ];
  977.  
  978.     return(ret_val);
  979. }
  980.  
  981.