home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / lib / Xaw / List.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-21  |  28.8 KB  |  1,014 lines

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