Back to index

plt-scheme  4.2.1
xwMultiList.c
Go to the documentation of this file.
00001 /****************************************************************************
00002 
00003   Ugly-hacked MrEd version!
00004   (Allows lists with a virtual size > max-short)
00005 
00006 ***********************************************************************/
00007 
00008 /****************************************************************************
00009 
00010        MultiList.c
00011 
00012        This file contains the implementation of the Picasso List
00013        widget.  Its functionality is intended to be similar to
00014        The Athena List widget, with some extra features added.
00015 
00016        This code is loosely based on the Athena List source which
00017        is why the MIT copyright notice appears below.
00018 
00019        The code was changed substantially in V3.4 to change the
00020        action/callback interface which was unnecessarily ugly.  Code
00021        using some features of the old interface may need to be changed.
00022        Hope the changes don't make people's lives too miserable.
00023 
00024  ****************************************************************************/
00025 
00026 /*
00027  * Author:
00028  *     Brian Totty
00029  *     Department of Computer Science
00030  *     University Of Illinois at Urbana-Champaign
00031  *     1304 West Springfield Avenue
00032  *     Urbana, IL 61801
00033  * 
00034  *     totty@cs.uiuc.edu
00035  *     
00036  */ 
00037 
00038 /*
00039  * Copyright 2004-2009 PLT Scheme Inc.
00040  * Copyright 1989 Massachusetts Institute of Technology
00041  *
00042  * Permission to use, copy, modify, distribute, and sell this software and its
00043  * documentation for any purpose is hereby granted without fee, provided that
00044  * the above copyright notice appear in all copies and that both that
00045  * copyright notice and this permission notice appear in supporting
00046  * documentation, and that the name of M.I.T. not be used in advertising or
00047  * publicity pertaining to distribution of the software without specific,
00048  * written prior permission.  M.I.T. makes no representations about the
00049  * suitability of this software for any purpose.  It is provided "as is"
00050  * without express or implied warranty.
00051  *
00052  * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
00053  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
00054  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00055  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
00056  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
00057  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00058  *
00059  * Original Athena Author:  Chris D. Peterson, MIT X Consortium
00060  */
00061 
00062 #include <stdio.h>
00063 #include <ctype.h>
00064 #include <stdlib.h>
00065 
00066 #include <X11/IntrinsicP.h>
00067 #include <X11/StringDefs.h>
00068 
00069 #include "xwMultiListP.h"
00070 #include "xwTabString.h"
00071 
00072 /*===========================================================================*
00073 
00074           D E C L A R A T I O N S    A N D    D E F I N I T I O N S
00075 
00076  *===========================================================================*/
00077 
00078 Pixmap XmuCreateStippledPixmap();
00079 extern void XawInitializeWidgetSet();
00080 extern int wxGetMultiClickTime(Display*);
00081 
00082 #define       SUPERCLASS    &(coreClassRec)
00083 
00084 #ifdef WX_USE_XFT
00085 # define      FontAscent(f, xf)    (xf ? (xf)->ascent : (f)->max_bounds.ascent)
00086 # define      FontDescent(f, xf)   (xf ? (xf)->descent : (f)->max_bounds.descent)
00087 #else
00088 # define      FontAscent(f, xf)    ((f)->max_bounds.ascent)
00089 # define      FontDescent(f, xf)   ((f)->max_bounds.descent)
00090 #endif
00091 
00092 #define       FontH(f, xf)  (FontAscent(f, xf) + FontDescent(f, xf) + 2)
00093 #define       FontW(f,s,w)  (XfwfTextWidth(f,s,strlen(s), MultiListTabs(w)) + 1)
00094 #define       FontMaxCharW(f)      ((f)->max_bounds.rbearing-(f)->min_bounds.lbearing+1)
00095 
00096 #ifndef abs
00097 #define abs(a)                     ((a) < 0 ? -(a) : (a))
00098 #endif
00099 
00100 #define max(a,b)            ((a) > (b) ? (a) : (b))
00101 #define min(a,b)            ((a) < (b) ? (a) : (b))
00102 #define XtStrlen(s)         ((s) ? strlen(s) : 0)
00103 
00104 #define       TypeAlloc(t,n)              (t *)malloc(sizeof(t) * n)
00105 #define       StrCopy(s)           strcpy(TypeAlloc(char,strlen(s)+1),s)
00106 #define       StrCopyRetLength(s,lp)      strcpy(TypeAlloc(char,(*lp=(strlen(s)+1))),s)
00107 
00108 #define CoreFieldOffset(f)  XtOffset(Widget,core.f)
00109 #define MultiListFieldOffset(f)    XtOffset(XfwfMultiListWidget,multiList.f)
00110 
00111 /*===========================================================================*
00112 
00113         I N T E R N A L    P R O C E D U R E    D E C L A R A T I O N S
00114 
00115  *===========================================================================*/
00116 
00117 #if (!NeedFunctionPrototypes)
00118 
00119 static void                 Initialize();
00120 static void                 Redisplay();
00121 static XtGeometryResult            PreferredGeometry();
00122 static void                 Resize();
00123 static Boolean                     SetValues();
00124 
00125 static void                 DestroyOldData();
00126 static void                 InitializeNewData();
00127 static void                 CreateNewGCs();
00128 
00129 static void                 RedrawAll();
00130 static void                 RedrawItem();
00131 static void                 RedrawRowColumn();
00132 
00133 static void                 PixelToRowColumn();
00134 static void                 RowColumnToPixels();
00135 static Boolean                     RowColumnToItem();
00136 static Boolean                     ItemToRowColumn();
00137 
00138 static void                 Select();
00139 static void                 SelectOne();
00140 static void                 Unselect();
00141 static void                 Toggle();
00142 static void                 Extend();
00143 static void                 Notify();
00144 
00145 #else
00146 
00147 static void          Initialize(Widget request, Widget new);
00148 static void          Redisplay(XfwfMultiListWidget mlw,
00149                             XEvent *event, Region rectangle_union);
00150 static XtGeometryResult PreferredGeometry(XfwfMultiListWidget mlw,
00151                             XtWidgetGeometry *parent_idea,
00152                             XtWidgetGeometry *our_idea);
00153 static void          Resize(XfwfMultiListWidget mlw);
00154 static Boolean              SetValues(XfwfMultiListWidget cpl,
00155                             XfwfMultiListWidget rpl,
00156                      XfwfMultiListWidget npl);
00157 static void          DestroyOldData(XfwfMultiListWidget mlw);
00158 static void          InitializeNewData(XfwfMultiListWidget mlw);
00159 static void          CreateNewGCs(XfwfMultiListWidget mlw);
00160 static void          RedrawAll(XfwfMultiListWidget mlw);
00161 static void          RedrawItem(XfwfMultiListWidget mlw, int item_index);
00162 static void          RedrawRowColumn(XfwfMultiListWidget mlw,
00163                             int row, int column);
00164 static void          PixelToRowColumn(XfwfMultiListWidget mlw,
00165                             int x, int y, int *row_ptr, int *column_ptr);
00166 static void          RowColumnToPixels(XfwfMultiListWidget mlw,
00167                             int row, int col, int *x_ptr, int *y_ptr,
00168                             int *w_ptr, int *h_ptr);
00169 static Boolean              RowColumnToItem(XfwfMultiListWidget mlw,
00170                             int row, int column, int *item_ptr);
00171 static Boolean              ItemToRowColumn(XfwfMultiListWidget mlw,
00172                             int item_index, int *row_ptr, int *column_ptr);
00173 static void          Select(XfwfMultiListWidget mlw, XEvent *event,
00174                             String *params, Cardinal *num_params);
00175 static void          SelectOne(XfwfMultiListWidget mlw, XEvent *event,
00176                             String *params, Cardinal *num_params);
00177 static void          Unselect(XfwfMultiListWidget mlw, XEvent *event,
00178                             String *params, Cardinal *num_params);
00179 static void          Toggle(XfwfMultiListWidget mlw, XEvent *event,
00180                             String *params, Cardinal *num_params);
00181 static void          Extend(XfwfMultiListWidget mlw, XEvent *event,
00182                             String *params, Cardinal *num_params);
00183 static void          Notify(XfwfMultiListWidget mlw, XEvent *event,
00184                             String *params, Cardinal *num_params);
00185 #endif
00186 
00187 /*===========================================================================*
00188 
00189               R E S O U R C E    I N I T I A L I Z A T I O N
00190 
00191  *===========================================================================*/
00192 
00193 static XtResource resources[] =
00194 {
00195        {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
00196            CoreFieldOffset(width), XtRString, "0"},
00197        {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
00198            CoreFieldOffset(height), XtRString, "0"},
00199        {XtNbackground, XtCBackground, XtRPixel, sizeof(Pixel),
00200            CoreFieldOffset(background_pixel),XtRString,"XtDefaultBackground"},
00201 
00202        {XtNhighlightForeground, XtCHForeground, XtRPixel, sizeof(Pixel),
00203            MultiListFieldOffset(highlight_fg), XtRString, "XtDefaultBackground"},
00204        {XtNhighlightBackground, XtCHBackground, XtRPixel, sizeof(Pixel),
00205            MultiListFieldOffset(highlight_bg), XtRString, "XtDefaultForeground"},
00206        {XtNcolumnSpacing, XtCSpacing, XtRDimension, sizeof(Dimension),
00207            MultiListFieldOffset(column_space), XtRImmediate, (caddr_t)8},
00208        {XtNrowSpacing, XtCSpacing, XtRDimension, sizeof(Dimension),
00209            MultiListFieldOffset(row_space), XtRImmediate, (caddr_t)0},
00210        {XtNdefaultColumns, XtCColumns, XtRInt,  sizeof(int),
00211            MultiListFieldOffset(default_cols), XtRImmediate, (caddr_t)1},
00212        {XtNforceColumns, XtCColumns, XtRBoolean, sizeof(Boolean),
00213            MultiListFieldOffset(force_cols), XtRString, (caddr_t) "False"},
00214        {XtNpasteBuffer, XtCBoolean, XtRBoolean, sizeof(Boolean),
00215            MultiListFieldOffset(paste), XtRString, (caddr_t) "False"},
00216        {XtNnumberStrings, XtCNumberStrings, XtRInt,  sizeof(int),
00217            MultiListFieldOffset(nitems), XtRImmediate, (caddr_t)0},
00218        {XtNfont,  XtCFont, XtRFontStruct, sizeof(XFontStruct *),
00219            MultiListFieldOffset(font),XtRString, "XtDefaultFont"},
00220 #ifdef WX_USE_XFT
00221        {XtNmlXftFont,  XtCMLXftFont, XtRPointer, sizeof(void*),
00222          MultiListFieldOffset(xft_font),XtRPointer, (XtPointer)0},
00223 #endif
00224        {XtNlist, XtCList, XtRPointer, sizeof(char **),
00225            MultiListFieldOffset(list), XtRString, NULL},
00226        {XtNsensitiveArray, XtCList, XtRPointer, sizeof(Boolean *),
00227            MultiListFieldOffset(sensitive_array), XtRString, NULL},
00228        {XtNcallback, XtCCallback, XtRCallback, sizeof(caddr_t),
00229            MultiListFieldOffset(callback), XtRCallback, NULL},
00230        {XtNmaxSelectable, XtCValue, XtRInt, sizeof(int),
00231            MultiListFieldOffset(max_selectable), XtRImmediate, (caddr_t) 1},
00232 
00233        {XtNoffset, XtCValue, XtRInt, sizeof(int),
00234            MultiListFieldOffset(offset), XtRString, "0"},
00235 
00236        {XtNshadeSurplus, XtCBoolean, XtRBoolean, sizeof(Boolean),
00237            MultiListFieldOffset(shade_surplus), XtRString, "True"},
00238 
00239        {XtNcolumnWidth, XtCValue, XtRDimension, sizeof(Dimension),
00240            MultiListFieldOffset(col_width), XtRImmediate, (caddr_t)0},
00241        {XtNrowHeight, XtCValue, XtRDimension, sizeof(Dimension),
00242            MultiListFieldOffset(row_height), XtRImmediate, (caddr_t)0},
00243 
00244        {XtNtablist, XtCTablist, XtRString, sizeof(int *),
00245            MultiListFieldOffset(tablist), XtRImmediate, (XtPointer)NULL },
00246 
00247        {XtNclickExtends, XtCBoolean, XtRBoolean, sizeof(Boolean),
00248             MultiListFieldOffset(clickExtends), XtRString, "False"},
00249 
00250        {XtNdrawgray, XtCBoolean, XtRBoolean, sizeof(Boolean),
00251             MultiListFieldOffset(drawgray), XtRString, "False"}
00252 
00253 };
00254 
00255 /*===========================================================================*
00256 
00257         A C T I O N    A N D    T R A N S L A T I O N    T A B L E S
00258 
00259  *===========================================================================*/
00260 
00261 static char defaultTranslations[] =
00262 "      Ctrl <Btn1Down>:                   Toggle()\n\
00263        Shift <Btn1Down>:                  SelectOne()\n\
00264        <Btn1Down>:                         Select()\n\
00265        Button1 <Btn1Motion>:                     Extend()\n\
00266        <Btn1Up>:                          Notify()";
00267 
00268 static char extendTranslations[] =
00269 "      Ctrl <Btn1Down>:                   Toggle()\n\
00270        Shift <Btn1Down>:                  SelectOne()\n\
00271        <Btn1Down>:                         Toggle()\n\
00272        Button1 <Btn1Motion>:                     Extend()\n\
00273        <Btn1Up>:                          Notify()";
00274 
00275 static XtActionsRec actions[] =
00276 {
00277        {"Select",                         (XtActionProc)Select},
00278        {"Unselect",                       (XtActionProc)Unselect},
00279        {"Toggle",                         (XtActionProc)Toggle},
00280        {"Extend",                         (XtActionProc)Extend},
00281        {"SelectOne",                      (XtActionProc)SelectOne},
00282        {"Notify",                         (XtActionProc)Notify},
00283        {NULL,                             (XtActionProc)NULL}
00284 };
00285 
00286 /*===========================================================================*
00287 
00288                     C L A S S    A L L O C A T I O N
00289 
00290  *===========================================================================*/
00291 
00292 XfwfMultiListClassRec xfwfMultiListClassRec =
00293 {
00294        {
00295               /* superclass        */     (WidgetClass)SUPERCLASS,
00296               /* class_name        */     "XfwfMultiList",
00297               /* widget_size              */     sizeof(XfwfMultiListRec),
00298               /* class_initialize  */     NULL,
00299               /* class_part_initialize*/  NULL,
00300               /* class_inited             */     FALSE,
00301               /* initialize        */     (XtInitProc)Initialize,
00302               /* initialize_hook   */     NULL,
00303               /* realize           */     XtInheritRealize,
00304               /* actions           */     actions,
00305               /* num_actions              */     XtNumber(actions),
00306               /* resources         */     resources,
00307               /* resource_count    */     XtNumber(resources),
00308               /* xrm_class         */     NULLQUARK,
00309               /* compress_motion   */     TRUE,
00310               /* compress_exposure */     FALSE,
00311               /* compress_enterleave      */     TRUE,
00312               /* visible_interest  */     FALSE,
00313               /* destroy           */     NULL,
00314               /* resize            */     (XtWidgetProc)Resize,
00315               /* expose            */     (XtExposeProc)Redisplay,
00316               /* set_values        */     (XtSetValuesFunc)SetValues,
00317               /* set_values_hook   */     NULL,
00318               /* set_values_almost */     XtInheritSetValuesAlmost,
00319               /* get_values_hook   */     NULL,
00320               /* accept_focus             */     NULL,
00321               /* version           */     XtVersion,
00322               /* callback_private  */     NULL,
00323               /* tm_table          */     defaultTranslations,
00324               /* query_geometry       */  (XtGeometryHandler)
00325                                                  PreferredGeometry,
00326               /* display_accelerator  */  XtInheritDisplayAccelerator,
00327               /* extension            */  NULL
00328        } /* Core Part */
00329 };
00330 
00331 WidgetClass xfwfMultiListWidgetClass = (WidgetClass)&xfwfMultiListClassRec;
00332 
00333 /*===========================================================================*
00334 
00335                        T O O L K I T    M E T H O D S
00336 
00337  *===========================================================================*/
00338 
00339 /*---------------------------------------------------------------------------*
00340 
00341        Initialize()
00342 
00343        This procedure is called by the X toolkit to initialize
00344        the widget instance.  The hook to this routine is in the
00345        initialize part of the core part of the class.
00346 
00347  *---------------------------------------------------------------------------*/
00348 
00349 /* ARGSUSED */
00350 static void Initialize(request,new)
00351 Widget request,new;
00352 {
00353        XfwfMultiListWidget mlw;
00354 
00355        mlw = (XfwfMultiListWidget)new;
00356        MultiListFG(mlw) = BlackPixelOfScreen(XtScreen(new));
00357        CreateNewGCs(mlw);
00358        InitializeNewData(mlw);
00359        MultiListLastRelease(mlw) = CurrentTime;
00360        MultiListTabs(mlw) = XfwfTablist2Tabs(MultiListTabList(mlw));
00361        MultiListWidth(mlw) = MultiListHeight(mlw) = 100;
00362        MultiListNumCols(mlw) = 1;
00363        MultiListNumRows(mlw) = 1;
00364        if (MultiListClickExtends(mlw)) {
00365          XtTranslations t = XtParseTranslationTable(extendTranslations);
00366          XtOverrideTranslations((Widget)new, t);
00367          XtFree((char *)t);
00368        }
00369 } /* Initialize */
00370 
00371 
00372 /*---------------------------------------------------------------------------*
00373 
00374        Redisplay(mlw,event,rectangle_union)
00375 
00376        This routine redraws the MultiList widget <mlw> based on the exposure
00377        region requested in <event>.
00378 
00379  *---------------------------------------------------------------------------*/
00380 
00381 /* ARGSUSED */
00382 static void Redisplay(mlw,event,rectangle_union)
00383 XfwfMultiListWidget mlw;
00384 XEvent *event;
00385 Region rectangle_union;
00386 {
00387        GC shade_gc;
00388        int i,x1,y1,w,h,x2,y2,row,col,ul_row,ul_col,lr_row,lr_col;
00389 
00390        if (MultiListShadeSurplus(mlw))
00391               shade_gc = MultiListGrayGC(mlw);
00392            else
00393               shade_gc = MultiListEraseGC(mlw);
00394        if (event == NULL)
00395        {
00396               XFillRectangle(XtDisplay(mlw),XtWindow(mlw),shade_gc,0,0,
00397                             MultiListWidth(mlw),MultiListHeight(mlw));
00398               for (i = 0; i < MultiListNumItems(mlw); i++) RedrawItem(mlw,i);
00399        }
00400            else
00401        {
00402               x1 = event->xexpose.x;
00403               y1 = event->xexpose.y;
00404               w = event->xexpose.width;
00405               h = event->xexpose.height;
00406               x2 = x1 + w;
00407               y2 = y1 + h;
00408               XFillRectangle(XtDisplay(mlw),XtWindow(mlw),
00409                             shade_gc,x1,y1,w,h);
00410               PixelToRowColumn(mlw,x1,y1,&ul_row,&ul_col);
00411               PixelToRowColumn(mlw,x2,y2,&lr_row,&lr_col);
00412               lr_row = min(lr_row,MultiListNumRows(mlw) - 1);
00413               lr_col = min(lr_col,MultiListNumCols(mlw) - 1);
00414               for (col = ul_col; col <= lr_col; col++)
00415               {
00416                      for (row = ul_row; row <= lr_row; row++)
00417                      {
00418                             RedrawRowColumn(mlw,row,col);
00419                      }
00420               }
00421        }
00422 } /* End Redisplay */
00423 
00424 
00425 /*---------------------------------------------------------------------------*
00426 
00427        PreferredGeometry(mlw,parent_idea,our_idea)
00428 
00429        This routine is called by the parent to tell us about the
00430        parent's idea of our width and/or height.  We then suggest
00431        our preference through <our_idea> and return the information
00432        to the parent.
00433 
00434  *---------------------------------------------------------------------------*/
00435 
00436 extern void XfwfCallComputeInside(Widget self,Position * x,Position * y,int * w,int * h);
00437 
00438 static XtGeometryResult PreferredGeometry(mlw,parent_idea,our_idea)
00439 XfwfMultiListWidget mlw;
00440 XtWidgetGeometry *parent_idea,*our_idea;
00441 {
00442         Position px, py;
00443        int nw,nh;
00444        Widget parent;
00445 
00446        parent = XtParent(mlw);
00447        XfwfCallComputeInside(parent, &px, &py, &nw, &nh);
00448 
00449        our_idea->request_mode |= (CWWidth | CWHeight);
00450        our_idea->width = nw;
00451        our_idea->height = nh;
00452 
00453        return XtGeometryAlmost;
00454 } /* End PreferredGeometry */
00455 
00456 
00457 /*---------------------------------------------------------------------------*
00458 
00459        Resize(mlw)
00460 
00461        This function is called when the widget is being resized.  It
00462        recalculates the layout of the widget.
00463 
00464  *---------------------------------------------------------------------------*/
00465 
00466 static void Resize(mlw)
00467 XfwfMultiListWidget mlw;
00468 {
00469   MultiListColWidth(mlw) = MultiListWidth(mlw);
00470 } /* End Resize */
00471 
00472 
00473 /*---------------------------------------------------------------------------*
00474 
00475        SetValues(cpl,rpl,npl)
00476 
00477        This routine is called when the user is changing resources.  <cpl>
00478        is the current widget before the user's changes have been instituted.
00479        <rpl> includes the original changes as requested by the user.  <npl>
00480        is the new resulting widget with the requested changes and with all
00481        superclass changes already made.
00482 
00483  *---------------------------------------------------------------------------*/
00484 
00485 /*ARGSUSED*/
00486 static Boolean SetValues(cpl,rpl,npl)
00487 XfwfMultiListWidget cpl,rpl,npl;
00488 {
00489        Boolean redraw,recalc;
00490 
00491        redraw = False;
00492        recalc = False;
00493 
00494               /* Graphic Context Changes */
00495 
00496        if ((MultiListFG(cpl) != MultiListFG(npl)) ||
00497            (MultiListBG(cpl) != MultiListBG(npl)) ||
00498            (MultiListHighlightFG(cpl) != MultiListHighlightFG(npl)) ||
00499            (MultiListHighlightBG(cpl) != MultiListHighlightBG(npl)) ||
00500            (MultiListFont(cpl) != MultiListFont(npl)) ||
00501            (MultiListXftFont(cpl) != MultiListXftFont(npl)))
00502        {
00503               XtDestroyGC(MultiListEraseGC(cpl));
00504               XtDestroyGC(MultiListDrawGC(cpl));
00505               XtDestroyGC(MultiListHighlightForeGC(cpl));
00506               XtDestroyGC(MultiListHighlightBackGC(cpl));
00507               XtDestroyGC(MultiListGrayGC(cpl));
00508               CreateNewGCs(npl);
00509               redraw = True;
00510        }
00511 
00512               /* Changes That Require Redraw */
00513 
00514        if ((MultiListSensitive(cpl) != MultiListSensitive(npl)) ||
00515            (MultiListAncesSensitive(cpl) != MultiListAncesSensitive(npl)) ||
00516            (MultiListDrawGray(cpl) != MultiListDrawGray(npl)))
00517        {
00518               redraw = True;
00519        }
00520 
00521               /* Changes That Require Data Initialization */
00522 
00523        if ((MultiListList(cpl) != MultiListList(npl)) ||
00524            (MultiListMaxSelectable(cpl) != MultiListMaxSelectable(npl)) ||
00525            (MultiListNumItems(cpl) != MultiListNumItems(npl)) ||
00526            (MultiListSensitiveArray(cpl) != MultiListSensitiveArray(npl)))
00527        {
00528               DestroyOldData(cpl);
00529               InitializeNewData(npl);
00530               recalc = True;
00531               redraw = True;
00532        }
00533 
00534        if (MultiListTabList(cpl) != MultiListTabList(npl))
00535        {
00536               if (MultiListTabs(cpl))
00537                      XtFree( (char *) MultiListTabs(cpl));
00538               MultiListTabs(npl) = XfwfTablist2Tabs(MultiListTabList(npl));
00539        }
00540 
00541               /* Changes That Require Recalculating Coordinates */
00542 
00543        if ((MultiListWidth(cpl) != MultiListWidth(npl)) ||
00544            (MultiListHeight(cpl) != MultiListHeight(npl)) ||
00545            (MultiListColumnSpace(cpl) != MultiListColumnSpace(npl)) ||
00546            (MultiListRowSpace(cpl) != MultiListRowSpace(npl)) ||
00547            (MultiListDefaultCols(cpl) != MultiListDefaultCols(npl)) ||
00548            ((MultiListForceCols(cpl) != MultiListForceCols(npl)) &&
00549             (MultiListNumCols(cpl) != MultiListNumCols(npl))) ||
00550            (MultiListFont(cpl) != MultiListFont(npl)) ||
00551            (MultiListXftFont(cpl) != MultiListXftFont(npl)))
00552        {
00553               recalc = True;
00554               redraw = True;
00555        }
00556 
00557        if (MultiListOffset(cpl) != MultiListOffset(npl))
00558          redraw = True;
00559 
00560 
00561        if (MultiListColWidth(cpl) != MultiListColWidth(npl))
00562        {
00563               XtWarning("columnWidth Resource Is Read-Only");
00564               MultiListColWidth(npl) = MultiListColWidth(cpl);
00565        }
00566        if (MultiListRowHeight(cpl) != MultiListRowHeight(npl))
00567        {
00568               XtWarning("rowHeight Resource Is Read-Only");
00569               MultiListRowHeight(npl) = MultiListRowHeight(cpl);
00570        }
00571 
00572        if (!XtIsRealized((Widget)cpl))
00573               return(False);
00574            else
00575               return(redraw);
00576 } /* End SetValues */
00577 
00578 /*===========================================================================*
00579 
00580                   D A T A    I N I T I A L I Z A T I O N
00581 
00582  *===========================================================================*/
00583 
00584 /*---------------------------------------------------------------------------*
00585 
00586        DestroyOldData(mlw)
00587 
00588        This routine frees the internal list item array and sets the
00589        item count to 0.  This is normally done immediately before
00590        calling InitializeNewData() to rebuild the internal item
00591        array from new user specified arrays.
00592 
00593  *---------------------------------------------------------------------------*/
00594 
00595 static void DestroyOldData(mlw)
00596 XfwfMultiListWidget mlw;
00597 {
00598        int i;
00599 
00600        if (MultiListItemArray(mlw) != NULL)      /* Free Old List */
00601        {
00602               for (i = 0; i < MultiListNumItems(mlw); i++)
00603               {
00604                      free(MultiListItemString(MultiListNthItem(mlw,i)));
00605               }
00606               free((char *)MultiListItemArray(mlw));
00607        }
00608        if (MultiListSelArray(mlw) != NULL)
00609            free((char *)MultiListSelArray(mlw));
00610        MultiListSelArray(mlw) = NULL;
00611        MultiListNumSelected(mlw) = 0;
00612        MultiListItemArray(mlw) = NULL;
00613        MultiListNumItems(mlw) = 0;
00614 } /* End DestroyOldData */
00615 
00616 
00617 /*---------------------------------------------------------------------------*
00618 
00619        InitializeNewData(mlw)
00620 
00621        This routine takes a MultiList widget <mlw> and builds up new
00622        data item tables based on the string list and the sensitivity array.
00623        All previous data should have already been freed.  If the number
00624        of items is 0, they will be counted, so the array must be NULL
00625        terminated.  If the list of strings is NULL, this is treated as
00626        a list of 0 elements.  If the sensitivity array is NULL, all
00627        items are treated as sensitive.
00628 
00629        When this routine is done, the string list and sensitivity array
00630        fields will all be set to NULL, and the widget will not reference
00631        them again.
00632 
00633  *---------------------------------------------------------------------------*/
00634 
00635 static void InitializeNewData(mlw)
00636 XfwfMultiListWidget mlw;
00637 {
00638        int i;
00639        XfwfMultiListItem *item;
00640        String *string_array;
00641 
00642        string_array = MultiListList(mlw);
00643        if (string_array == NULL) MultiListNumItems(mlw) = 0;
00644 
00645        if (MultiListNumItems(mlw) == 0)          /* Count Elements */
00646        {
00647               if (string_array == NULL)          /* No elements */
00648               {
00649                      MultiListNumItems(mlw) = 0;
00650               }
00651                   else
00652               {
00653                      for (i = 0; string_array[i] != NULL; i++);
00654                      MultiListNumItems(mlw) = i;
00655               }
00656        }
00657        if (MultiListNumItems(mlw) == 0)          /* No Items */
00658        {
00659               MultiListItemArray(mlw) = NULL;
00660        }
00661            else
00662        {
00663               MultiListItemArray(mlw) =
00664                      TypeAlloc(XfwfMultiListItem,MultiListNumItems(mlw));
00665               for (i = 0; i < MultiListNumItems(mlw); i++)
00666               {
00667                      item = MultiListNthItem(mlw,i);
00668                      if (MultiListSensitiveArray(mlw) == NULL ||
00669                          (MultiListSensitiveArray(mlw)[i] == True))
00670                      {
00671                             MultiListItemSensitive(item) = True;
00672                      }
00673                          else
00674                      {
00675                             MultiListItemSensitive(item) = False;
00676                      }
00677                      MultiListItemString(item) = StrCopy(string_array[i]);
00678                      MultiListItemHighlighted(item) = False;
00679               }
00680        }
00681        if (MultiListMaxSelectable(mlw) == 0)
00682        {
00683               MultiListSelArray(mlw) = NULL;
00684               MultiListNumSelected(mlw) = 0;
00685        }
00686            else
00687        {
00688               MultiListSelArray(mlw) =
00689                      TypeAlloc(int,MultiListMaxSelectable(mlw));
00690               MultiListNumSelected(mlw) = 0;
00691        }
00692 
00693        MultiListList(mlw) = NULL;
00694        MultiListSensitiveArray(mlw) = NULL;
00695 } /* End InitializeNewData */
00696               
00697 
00698 /*---------------------------------------------------------------------------*
00699 
00700        CreateNewGCs(mlw)
00701 
00702        This routine takes a MultiList widget <mlw> and creates a new set of
00703        graphic contexts for the widget based on the colors, fonts, etc.
00704        in the widget.  Any previous GCs are assumed to have already been
00705        destroyed.
00706 
00707  *---------------------------------------------------------------------------*/
00708 extern Boolean  get_scaled_color(Widget,float ,Pixel ,Pixel *);
00709 
00710 static void CreateNewGCs(mlw)
00711 XfwfMultiListWidget mlw;
00712 {
00713        XGCValues values;
00714        unsigned int attribs;
00715 
00716        attribs = GCForeground | GCBackground;
00717        values.foreground = MultiListFG(mlw);
00718        values.background = MultiListBG(mlw);
00719        if (MultiListFont(mlw)) {
00720          values.font = MultiListFont(mlw)->fid;
00721          attribs |= GCFont;
00722        }
00723        MultiListDrawGC(mlw) = XtGetGC((Widget)mlw,attribs,&values);
00724 
00725        values.foreground = MultiListBG(mlw);
00726        MultiListEraseGC(mlw) = XtGetGC((Widget)mlw,attribs,&values);
00727 
00728        values.foreground = MultiListHighlightFG(mlw);
00729        values.background = MultiListHighlightBG(mlw);
00730        MultiListHighlightForeGC(mlw) = XtGetGC((Widget)mlw,attribs,&values);
00731 
00732        values.foreground = MultiListHighlightBG(mlw);
00733        values.background = MultiListHighlightBG(mlw);
00734        MultiListHighlightBackGC(mlw) = XtGetGC((Widget)mlw,attribs,&values);
00735 
00736        if (wx_enough_colors(XtScreen(mlw))) {
00737          get_scaled_color((Widget)mlw, 0.6, MultiListBG(mlw), &values.foreground);
00738        } else {
00739          attribs |= GCTile | GCFillStyle;
00740          values.foreground = MultiListFG(mlw);
00741          values.background = MultiListBG(mlw);
00742          values.fill_style = FillTiled;
00743          values.tile = XmuCreateStippledPixmap(XtScreen(mlw),MultiListFG(mlw),
00744                                           MultiListBG(mlw),MultiListDepth(mlw));
00745        }
00746        MultiListGrayGC(mlw) = XtGetGC((Widget)mlw,attribs,&values);
00747 } /* End CreateNewGCs */
00748 
00749 /*===========================================================================*
00750 
00751                     R E D R A W    R O U T I N E S
00752 
00753  *===========================================================================*/
00754 
00755 /*---------------------------------------------------------------------------*
00756 
00757        RedrawAll(mlw)
00758 
00759        This routine simple calls Redisplay to redraw the entire
00760        MultiList widget <mlw>.
00761 
00762  *---------------------------------------------------------------------------*/
00763 
00764 static void RedrawAll(mlw)
00765 XfwfMultiListWidget mlw;
00766 {
00767        Redisplay(mlw,NULL,NULL);
00768 } /* End RedrawAll */
00769 
00770 
00771 /*---------------------------------------------------------------------------*
00772 
00773        RedrawItem(mlw,item_index)
00774 
00775        This routine redraws the item with index <item_index> in the
00776        MultiList widget <mlw>.  If the item number is bad, nothing is drawn.
00777 
00778  *---------------------------------------------------------------------------*/
00779 
00780 static void RedrawItem(mlw,item_index)
00781 XfwfMultiListWidget mlw;
00782 int item_index;
00783 {
00784        int row,column;
00785 
00786        if (ItemToRowColumn(mlw,item_index,&row,&column))
00787        {
00788               RedrawRowColumn(mlw,row,column);
00789        }
00790 } /* End RedrawItem */
00791 
00792 
00793 /*---------------------------------------------------------------------------*
00794 
00795        RedrawRowColumn(mlw,row,column)
00796 
00797        This routine paints the item in row/column position <row>,<column>
00798        on the MultiList widget <mlw>.  If the row/column coordinates are
00799        outside the widget, nothing is drawn.  If the position is empty,
00800        blank space is drawn.
00801 
00802  *---------------------------------------------------------------------------*/
00803 
00804 static void RedrawRowColumn(mlw,row,column)
00805 XfwfMultiListWidget mlw;
00806 int row,column;
00807 {
00808   GC bg_gc=0,fg_gc=0;
00809   XfwfMultiListItem *item=NULL;
00810   int ul_x,ul_y,str_x,str_y,w,h,item_index,has_item,text_h;
00811   int xmode;
00812        
00813   if (!XtIsRealized((Widget)mlw)) return;
00814   has_item = RowColumnToItem(mlw,row,column,&item_index);
00815   RowColumnToPixels(mlw,row,column,&ul_x,&ul_y,&w,&h);
00816 
00817   if (has_item == False)    /* No Item */
00818     {
00819       if (MultiListShadeSurplus(mlw))
00820        bg_gc = MultiListGrayGC(mlw);
00821       else
00822        bg_gc = MultiListEraseGC(mlw);
00823       xmode = 1;
00824     } else {
00825       item = MultiListNthItem(mlw,item_index);
00826       if ((!MultiListSensitive(mlw)) ||
00827          (MultiListDrawGray(mlw)) ||
00828          (!MultiListItemSensitive(item))) /* Insensitive */
00829        {
00830          if (MultiListItemHighlighted(item)) /* Selected */
00831            {
00832              bg_gc = MultiListGrayGC(mlw);
00833              fg_gc = MultiListEraseGC(mlw);
00834              xmode = -1;
00835            }
00836          else               /* !Selected */
00837            {
00838              bg_gc = MultiListEraseGC(mlw);
00839              fg_gc = MultiListGrayGC(mlw);
00840              xmode = 0;
00841            }
00842        }
00843       else                  /* Sensitive */
00844        {
00845          if (MultiListItemHighlighted(item)) /* Selected */
00846            {
00847              xmode = -1;
00848              bg_gc = MultiListHighlightBackGC(mlw);
00849              fg_gc = MultiListHighlightForeGC(mlw);
00850            }
00851          else               /* !Selected */
00852            {
00853              xmode = 1;
00854              bg_gc = MultiListEraseGC(mlw);
00855              fg_gc = MultiListDrawGC(mlw);
00856            }
00857        }
00858     }
00859   XFillRectangle(XtDisplay(mlw),XtWindow(mlw),bg_gc,ul_x,ul_y,w,h);
00860   if (has_item == True) {
00861     text_h = min(FontH(MultiListFont(mlw), MultiListXftFont(mlw)) +
00862                (int)MultiListRowSpace(mlw),(int)MultiListRowHeight(mlw));
00863     str_x = ul_x + MultiListColumnSpace(mlw) / 2;
00864     str_y = ul_y + FontAscent(MultiListFont(mlw), MultiListXftFont(mlw)) +
00865       ((int)MultiListRowHeight(mlw) - text_h) / 2;
00866     XfwfDrawString(XtDisplay(mlw),XtWindow(mlw),
00867                  (MultiListXftFont(mlw) ? NULL : fg_gc),
00868                  str_x,str_y,MultiListItemString(item),
00869                  strlen(MultiListItemString(item)),
00870                  MultiListTabs(mlw), NULL, 
00871                  MultiListXftFont(mlw), xmode,
00872                  0, NULL, 0);
00873   }
00874 } /* End RedrawRowColumn */
00875        
00876 /*===========================================================================*
00877 
00878                I T E M    L O C A T I O N    R O U T I N E S
00879 
00880  *===========================================================================*/
00881 
00882 /*---------------------------------------------------------------------------*
00883 
00884        void PixelToRowColumn(mlw,x,y,row_ptr,column_ptr)
00885 
00886        This routine takes pixel coordinates <x>, <y> and converts
00887        the pixel coordinate into a row/column coordinate.  This row/column
00888        coordinate can then easily be converted into the specific item
00889        in the list via the function RowColumnToItem().
00890 
00891        If the pixel lies in blank space outside of the items, the
00892        row & column numbers will be outside of the range of normal
00893        row & columns numbers, but will correspond to the row & column
00894        of the item, if an item was actually there.
00895 
00896  *---------------------------------------------------------------------------*/
00897 
00898 static void PixelToRowColumn(mlw,x,y,row_ptr,column_ptr)
00899 XfwfMultiListWidget mlw;
00900 int x,y,*row_ptr,*column_ptr;
00901 {
00902        *row_ptr = (y / (int)MultiListRowHeight(mlw)) + MultiListOffset(mlw);
00903        *column_ptr = x / (int)MultiListColWidth(mlw);
00904 } /* End PixelToRowColumn */
00905 
00906 /*---------------------------------------------------------------------------*
00907 
00908        void RowColumnToPixels(mlw,row,col,x_ptr,y_ptr,w_ptr,h_ptr)
00909 
00910        This routine takes a row/column coordinate <row>,<col> and
00911        converts it into the bounding pixel rectangle which is returned.
00912 
00913  *---------------------------------------------------------------------------*/
00914 
00915 static void RowColumnToPixels(mlw,row,col,x_ptr,y_ptr,w_ptr,h_ptr)
00916 XfwfMultiListWidget mlw;
00917 int row,col,*x_ptr,*y_ptr,*w_ptr,*h_ptr;
00918 {
00919        *x_ptr = col * MultiListColWidth(mlw);
00920        *y_ptr = (row - MultiListOffset(mlw)) * MultiListRowHeight(mlw);
00921        *w_ptr = MultiListColWidth(mlw);
00922        *h_ptr = MultiListRowHeight(mlw);
00923 } /* End RowColumnToPixels */
00924 
00925 /*---------------------------------------------------------------------------*
00926 
00927        Boolean RowColumnToItem(mlw,row,column,item_ptr)
00928 
00929        This routine takes a row number <row> and a column number <column>
00930        and tries to resolve this row and column into the index of the
00931        item in this position of the MultiList widget <mlw>.  The resulting
00932        item index is placed through <item_ptr>.  If there is no item at
00933        this location, False is returned, else True is returned.
00934 
00935  *---------------------------------------------------------------------------*/
00936 
00937 static Boolean RowColumnToItem(mlw,row,column,item_ptr)
00938 XfwfMultiListWidget mlw;
00939 int row,column,*item_ptr;
00940 {
00941        register int x_stride,y_stride;
00942 
00943        if (row < 0 || row >= MultiListNumRows(mlw) ||
00944            column < 0 || column >= MultiListNumCols(mlw))
00945        {
00946               return(False);
00947        }
00948        x_stride = MultiListNumRows(mlw);
00949        y_stride = 1;
00950        *item_ptr = row * y_stride + column * x_stride;
00951        if (*item_ptr >= MultiListNumItems(mlw))
00952               return(False);
00953            else
00954               return(True);
00955 } /* End RowColumnToItem */
00956 
00957 
00958 /*---------------------------------------------------------------------------*
00959 
00960        Boolean ItemToRowColumn(mlw,item_index,row_ptr,column_ptr)
00961 
00962        This routine takes an item number <item_index> and attempts
00963        to convert the index into row and column numbers stored through
00964        <row_ptr> and <column_ptr>.  If the item number does not
00965        corespond to a valid item, False is returned, else True is
00966        returned.
00967 
00968  *---------------------------------------------------------------------------*/
00969 
00970 static Boolean ItemToRowColumn(mlw,item_index,row_ptr,column_ptr)
00971 XfwfMultiListWidget mlw;
00972 int item_index,*row_ptr,*column_ptr;
00973 {
00974        if (item_index < 0 || item_index >= MultiListNumItems(mlw))
00975        {
00976               return(False);
00977        }
00978        *row_ptr = item_index % MultiListNumRows(mlw);
00979        *column_ptr = item_index / MultiListNumRows(mlw);
00980 
00981        return(True);
00982 } /* End ItemToRowColumn */
00983 
00984 /*===========================================================================*
00985 
00986                 E V E N T    A C T I O N    H A N D L E R S
00987 
00988  *===========================================================================*/
00989 
00990 /*---------------------------------------------------------------------------*
00991 
00992        Select(mlw,event,params,num_params)
00993 
00994        This action handler is called when a user selects an item in the
00995        MultiList.  This action first unselects all previously selected
00996        items, then selects the item under the mouse, if it is not a
00997        background gap, and if it is sensitive.
00998 
00999        The MultiListMostRecentItem(mlw) variable will be set to the
01000        item clicked on, or -1 if the item is background or insensitive.
01001        The MultiListMostRecentAct(mlw) variable will be set to
01002        XfwfMultiListActionHighlight, in case the selection region is extended.
01003 
01004  *---------------------------------------------------------------------------*/
01005 
01006 /* ARGSUSED */
01007 static void Select(mlw,event,params,num_params)
01008 XfwfMultiListWidget mlw;
01009 XEvent *event;
01010 String *params;
01011 Cardinal *num_params;
01012 {
01013        int click_x,click_y;
01014        int status,item_index,row,column;
01015 
01016        click_x = event->xbutton.x;
01017        click_y = event->xbutton.y;
01018        PixelToRowColumn(mlw,click_x,click_y,&row,&column);
01019        MultiListMostRecentAct(mlw) = XfwfMultiListActionHighlight;
01020        status = RowColumnToItem(mlw,row,column,&item_index);
01021        if ((status == False) ||
01022            (!MultiListItemSensitive(MultiListNthItem(mlw,item_index))))
01023        {
01024                MultiListMostRecentAct(mlw) = XfwfMultiListActionNothing;
01025               MultiListMostRecentItem(mlw) = -1;
01026        }
01027            else
01028        {
01029                XfwfMultiListUnhighlightAll(mlw);
01030               MultiListMostRecentItem(mlw) = item_index;
01031               XfwfMultiListHighlightItem(mlw,item_index);
01032        }
01033 } /* End Select */
01034 
01035 
01036 /* ARGSUSED */
01037 static void SelectOne(mlw,event,params,num_params)
01038 XfwfMultiListWidget mlw;
01039 XEvent *event;
01040 String *params;
01041 Cardinal *num_params;
01042 {
01043        int click_x,click_y;
01044        int status,item_index,row,column;
01045 
01046        click_x = event->xbutton.x;
01047        click_y = event->xbutton.y;
01048        PixelToRowColumn(mlw,click_x,click_y,&row,&column);
01049        MultiListMostRecentAct(mlw) = XfwfMultiListActionHighlight;
01050        status = RowColumnToItem(mlw,row,column,&item_index);
01051        if ((status == False) ||
01052            (!MultiListItemSensitive(MultiListNthItem(mlw,item_index))))
01053        {
01054                MultiListMostRecentAct(mlw) = XfwfMultiListActionNothing;
01055               MultiListMostRecentItem(mlw) = -1;
01056        }
01057            else
01058        {
01059               MultiListMostRecentItem(mlw) = item_index;
01060               XfwfMultiListHighlightItem(mlw,item_index);
01061        }
01062 } /* End Select */
01063 
01064 
01065 /*---------------------------------------------------------------------------*
01066 
01067        Unselect(mlw,event,params,num_params)
01068 
01069        This function unselects the single text item pointed to by the
01070        mouse, if any.  Any remaining selected entries are left selected.
01071 
01072        The MultiListMostRecentItem(mlw) variable will be set to -1, and
01073        the MultiListMostRecentAct(mlw) variable will be set to
01074        XfwfMultiListActionUnhighlight, in case the deselection region is
01075        extended.
01076        
01077  *---------------------------------------------------------------------------*/
01078 
01079 /* ARGSUSED */
01080 static void Unselect(mlw,event,params,num_params)
01081 XfwfMultiListWidget mlw;
01082 XEvent *event;
01083 String *params;
01084 Cardinal *num_params;
01085 {
01086        int click_x,click_y;
01087        int status,item_index,row,column;
01088 
01089        click_x = event->xbutton.x;
01090        click_y = event->xbutton.y;
01091        PixelToRowColumn(mlw,click_x,click_y,&row,&column);
01092        MultiListMostRecentItem(mlw) = -1;
01093        MultiListMostRecentAct(mlw) = XfwfMultiListActionUnhighlight;
01094        status = RowColumnToItem(mlw,row,column,&item_index);
01095        if ((status == True) &&
01096            (MultiListItemSensitive(MultiListNthItem(mlw,item_index)))) {
01097               XfwfMultiListUnhighlightItem(mlw,item_index);
01098        } else {
01099          MultiListMostRecentAct(mlw) = XfwfMultiListActionNothing;
01100        }
01101 } /* End Unselect */
01102 
01103 
01104 /*---------------------------------------------------------------------------*
01105 
01106        Toggle(mlw,event,params,num_params)
01107 
01108        This action handler implements the toggling of selection status
01109        for a single item.  Any remaining selected entries are left selected.
01110 
01111        If the mouse is not over a selectable text item, the
01112        MultiListMostRecentAct(mlw) variable is set to
01113        XfwfMultiListActionHighlight, in case the region is extended into
01114        selectable items later.  MultiListMostRecentItem(mlw) is set to -1.
01115 
01116        If the mouse is over a selectable text item, the item highlight is
01117        toggled.  If the item is currently selected, it becomes deselected.
01118        If unselected, the item becomes selected.  At the same time, the
01119        MultiListMostRecentAct(mlw) variable is set to
01120        XfwfMultiListActionHighlight if the item was not previously selected,
01121        or XfwfMultiListActionUnhighlight if the item was previously selected.
01122        MultiListMostRecentItem(mlw) is set to the index of the item clicked
01123        on if the item is selected, or -1 if it is unselected.
01124 
01125  *---------------------------------------------------------------------------*/
01126 
01127 /* ARGSUSED */
01128 static void Toggle(mlw,event,params,num_params)
01129 XfwfMultiListWidget mlw;
01130 XEvent *event;
01131 String *params;
01132 Cardinal *num_params;
01133 {
01134        int click_x,click_y;
01135        int status,item_index,row,column;
01136 
01137        click_x = event->xbutton.x;
01138        click_y = event->xbutton.y;
01139        PixelToRowColumn(mlw,click_x,click_y,&row,&column);
01140        status = RowColumnToItem(mlw,row,column,&item_index);
01141        if ((status == False) ||
01142            (!MultiListItemSensitive(MultiListNthItem(mlw,item_index))))
01143        {
01144                MultiListMostRecentAct(mlw) = XfwfMultiListActionNothing;
01145               MultiListMostRecentItem(mlw) = -1;
01146        }
01147            else
01148        {
01149               MultiListMostRecentAct(mlw) =
01150                      XfwfMultiListToggleItem(mlw,item_index);
01151               MultiListMostRecentItem(mlw) = item_index;
01152        }
01153 } /* End Toggle */
01154 
01155 
01156 /*---------------------------------------------------------------------------*
01157 
01158        Extend(mlw,event,params,num_params)
01159 
01160        This action handler implements the extension of a selection/
01161        deselection region.
01162 
01163        The MultiListMostRecentAct(mlw) variable is used to determine
01164        if items are to be selected or unselected.  This routine performs
01165        select or unselect actions on each item it is called on.
01166 
01167  *---------------------------------------------------------------------------*/
01168 
01169 /* ARGSUSED */
01170 static void Extend(mlw,event,params,num_params)
01171 XfwfMultiListWidget mlw;
01172 XEvent *event;
01173 String *params;
01174 Cardinal *num_params;
01175 {
01176        int click_x,click_y;
01177        int status,item_index,row,column;
01178 
01179        click_x = ((XMotionEvent*)event)->x;
01180        click_y = ((XMotionEvent*)event)->y;
01181        PixelToRowColumn(mlw,click_x,click_y,&row,&column);
01182        status = RowColumnToItem(mlw,row,column,&item_index);
01183        if ((status == True) &&
01184            (MultiListItemSensitive(MultiListNthItem(mlw,item_index))))
01185        {
01186          MultiListMostRecentItem(mlw) = item_index;
01187          if (MultiListMostRecentAct(mlw) == XfwfMultiListActionHighlight)
01188            XfwfMultiListHighlightItem(mlw,item_index);
01189          else if (MultiListMostRecentAct(mlw) == XfwfMultiListActionUnhighlight)
01190            XfwfMultiListUnhighlightItem(mlw,item_index);
01191        }
01192 } /* End Extend */
01193 
01194 
01195 /*---------------------------------------------------------------------------*
01196 
01197        Notify(mlw,event,params,num_params)
01198 
01199        This function performs the Notify action, which issues a callback
01200        after a selection/unselection has completed.  All callbacks on the
01201        callback list are invoked, and a XfxfMultiListReturnStruct describing
01202        the selection state is returned.
01203 
01204        In addition, if the XtNpasteBuffer resource is true and at least one
01205        text item is selected, all the selected items are placed in the X
01206        cut buffer (buf(0)) separated by newlines.
01207 
01208  *---------------------------------------------------------------------------*/
01209 
01210 /* ARGSUSED */
01211 static void Notify(mlw,event,params,num_params)
01212 XfwfMultiListWidget mlw;
01213 XEvent *event;
01214 String *params;
01215 Cardinal *num_params;
01216 {
01217        char *buffer;
01218        String string;
01219        int i,byte_count,item_index;
01220        XfwfMultiListReturnStruct ret_value;
01221 
01222        if (MultiListMostRecentAct(mlw) == XfwfMultiListActionNothing)
01223          return;
01224 
01225        /* handle double click events using the timestamp of event */
01226        if (event->xbutton.time - MultiListLastRelease(mlw)
01227            < wxGetMultiClickTime(XtDisplay(mlw)))
01228        {
01229            Select(mlw, event, params, num_params);
01230            MultiListMostRecentAct(mlw) = XfwfMultiListActionDClick;
01231        }
01232        MultiListLastRelease(mlw) = event->xbutton.time;
01233 
01234        if ((MultiListNumSelected(mlw) != 0) && MultiListPaste(mlw))
01235        {
01236               byte_count = 0;
01237               for (i = 0; i < MultiListNumSelected(mlw); i++)
01238               {
01239                      item_index = MultiListSelArray(mlw)[i];
01240                      string = MultiListItemString(MultiListNthItem(mlw,
01241                             item_index));
01242                      byte_count = byte_count + strlen(string) + 1;
01243               }
01244               buffer = (char *)malloc(byte_count);
01245               buffer[0] = '\0';
01246               for (i = 0; i < MultiListNumSelected(mlw); i++)
01247               {
01248                      if (i != 0) strcat(buffer,"\n");
01249                      item_index = MultiListSelArray(mlw)[i];
01250                      string = MultiListItemString(MultiListNthItem(mlw,
01251                             item_index));
01252                      strcat(buffer,string);
01253               }
01254               XStoreBytes(XtDisplay(mlw),buffer,byte_count);
01255               free(buffer);
01256        }
01257 
01258        ret_value.action = MultiListMostRecentAct(mlw);
01259        ret_value.item = MultiListMostRecentItem(mlw);
01260        if (ret_value.item == -1)
01261               ret_value.string = NULL;
01262            else
01263               ret_value.string = MultiListItemString(MultiListNthItem(mlw,
01264                      ret_value.item));
01265        ret_value.num_selected = MultiListNumSelected(mlw);
01266        ret_value.selected_items = MultiListSelArray(mlw);
01267        XtCallCallbacks((Widget)mlw,XtNcallback,(caddr_t)&ret_value);
01268 } /* End Notify */
01269 
01270 /*===========================================================================*
01271 
01272         U S E R    C A L L A B L E    U T I L I T Y    R O U T I N E S
01273 
01274  *===========================================================================*/
01275 
01276 /*---------------------------------------------------------------------------*
01277 
01278        Boolean XfwfMultiListHighlightItem(mlw,item_index)
01279 
01280        This routine selects an item with index <item_index> in the
01281        MultiList widget <mlw>.  If a maximum number of selections is specified
01282        and exceeded, the earliest selection will be unselected.  If
01283        <item_index> doesn't correspond to an item the most recently
01284        clicked item will be set to -1 and this routine will immediately
01285        return, otherwise the most recently clicked item will be set to the
01286        current item.  If the clicked on item is not sensitive, or if the
01287        click is not on an item, False is returned, else True is returned.
01288 
01289  *---------------------------------------------------------------------------*/
01290 
01291 Boolean XfwfMultiListHighlightItem(mlw,item_index)
01292 XfwfMultiListWidget mlw;
01293 int item_index;
01294 {
01295        XfwfMultiListItem *item;
01296 
01297        if (MultiListMaxSelectable(mlw) == 0) return(False);
01298        if (item_index < 0 || item_index >= MultiListNumItems(mlw))
01299        {
01300               MultiListMostRecentItem(mlw) = -1;
01301               return(False);
01302        }
01303        item = MultiListNthItem(mlw,item_index);
01304        if (MultiListItemSensitive(item) == False) return(False);
01305        MultiListMostRecentItem(mlw) = item_index;
01306        if (MultiListItemHighlighted(item) == True) return(True);
01307        if (MultiListNumSelected(mlw) == MultiListMaxSelectable(mlw))
01308        {
01309               XfwfMultiListUnhighlightItem(mlw,MultiListSelArray(mlw)[0]);
01310        }
01311        MultiListItemHighlighted(item) = True;
01312        MultiListSelArray(mlw)[MultiListNumSelected(mlw)] = item_index;
01313        ++ MultiListNumSelected(mlw);
01314        RedrawItem(mlw,item_index);
01315        return(True);
01316 } /* End XfwfMultiListHighlightItem */
01317 
01318 
01319 /*---------------------------------------------------------------------------*
01320 
01321        XfwfMultiListHighlightAll(mlw)
01322 
01323        This routine highlights all highlightable items in the MultiList
01324        widget <mlw>, up to the maximum number of allowed highlightable
01325        items;
01326 
01327  *---------------------------------------------------------------------------*/
01328 
01329 void XfwfMultiListHighlightAll(mlw)
01330 XfwfMultiListWidget mlw;
01331 {
01332        int i;
01333        XfwfMultiListItem *item;
01334 
01335        MultiListNumSelected(mlw) = 0;
01336        for (i = 0; i < MultiListNumItems(mlw); i++)
01337        {
01338               item = MultiListNthItem(mlw,i);
01339               MultiListItemHighlighted(item) = False;
01340        }
01341        for (i = 0; i < MultiListNumItems(mlw); i++)
01342        {
01343               if (MultiListNumSelected(mlw) == MultiListMaxSelectable(mlw))
01344                      break;
01345               item = MultiListNthItem(mlw,i);
01346               if (MultiListItemSensitive(item) == False) continue;
01347               MultiListItemHighlighted(item) = True;
01348               MultiListSelArray(mlw)[MultiListNumSelected(mlw)] = i;
01349               ++ MultiListNumSelected(mlw);
01350        }
01351        RedrawAll(mlw);
01352 } /* End XfwfMultiListHighlightAll */
01353 
01354 
01355 /*---------------------------------------------------------------------------*
01356 
01357        XfwfMultiListUnhighlightItem(mlw,item_index)
01358 
01359        This routine unselects the item with index <item_index> in the
01360        MultiList widget <mlw>.  If <item_index> doesn't correspond to a
01361        selected item, then nothing will happen.  Otherwise, the item
01362        is unselected and the selection array and count are updated.
01363 
01364  *---------------------------------------------------------------------------*/
01365 
01366 void XfwfMultiListUnhighlightItem(mlw,item_index)
01367 XfwfMultiListWidget mlw;
01368 int item_index;
01369 {
01370        int i;
01371        XfwfMultiListItem *item;
01372 
01373        if (MultiListMaxSelectable(mlw) == 0) return;
01374        if (item_index < 0 || item_index >= MultiListNumItems(mlw)) return;
01375        item = MultiListNthItem(mlw,item_index);
01376        if (MultiListItemHighlighted(item) == False) return;
01377        MultiListItemHighlighted(item) = False;
01378 
01379        for (i = 0; i < MultiListNumSelected(mlw); i++)
01380               if (MultiListSelArray(mlw)[i] == item_index) break;
01381        for (i = i + 1; i < MultiListNumSelected(mlw); i++)
01382               MultiListSelArray(mlw)[i - 1] = MultiListSelArray(mlw)[i];
01383        -- MultiListNumSelected(mlw);
01384 
01385        RedrawItem(mlw,item_index);
01386 } /* End XfwfMultiListUnhighlightItem */
01387 
01388 
01389 /*---------------------------------------------------------------------------*
01390 
01391        XfwfMultiListUnhighlightAll(mlw)
01392 
01393        This routine unhighlights all items in the MultiList widget <mlw>.
01394 
01395  *---------------------------------------------------------------------------*/
01396 
01397 void XfwfMultiListUnhighlightAll(mlw)
01398 XfwfMultiListWidget mlw;
01399 {
01400        int i;
01401        XfwfMultiListItem *item;
01402 
01403        for (i = 0; i < MultiListNumItems(mlw); i++)
01404        {
01405               item = MultiListNthItem(mlw,i);
01406               if (MultiListItemHighlighted(item))
01407                      XfwfMultiListUnhighlightItem(mlw,i);
01408        }
01409        MultiListNumSelected(mlw) = 0;
01410 } /* End XfwfMultiListUnhighlightAll */
01411 
01412 
01413 /*---------------------------------------------------------------------------*
01414 
01415        int XfwfMultiListToggleItem(mlw,item_index)
01416 
01417        This routine highlights the item with index <item_index>
01418        if it is unhighlighted and unhighlights it if it is already
01419        highlighted.  The action performed by the toggle is returned
01420        (XfwfMultiListActionHighlight or XfwfMultiListActionUnhighlight).
01421 
01422  *---------------------------------------------------------------------------*/
01423 
01424 int XfwfMultiListToggleItem(mlw,item_index)
01425 XfwfMultiListWidget mlw;
01426 int item_index;
01427 {
01428        XfwfMultiListItem *item;
01429 
01430        if (MultiListMaxSelectable(mlw) == 0)
01431               return(XfwfMultiListActionNothing);
01432        if (item_index < 0 || item_index >= MultiListNumItems(mlw))
01433               return(XfwfMultiListActionNothing);
01434        item = MultiListNthItem(mlw,item_index);
01435        if (MultiListItemSensitive(item) == False)
01436               return(XfwfMultiListActionNothing);
01437        if (MultiListItemHighlighted(item))
01438        {
01439               XfwfMultiListUnhighlightItem(mlw,item_index);
01440               return(XfwfMultiListActionUnhighlight);
01441        }
01442            else
01443        {
01444               XfwfMultiListHighlightItem(mlw,item_index);
01445               return(XfwfMultiListActionHighlight);
01446        }
01447 } /* End XfwfMultiListToggleItem */
01448 
01449 
01450 /*---------------------------------------------------------------------------*
01451 
01452        XfwfMultiListReturnStruct *XfwfMultiListGetHighlighted(mlw)
01453 
01454        This routine takes a MultiList widget <mlw> and returns a
01455        XfwfMultiListReturnStruct whose num_selected and selected_items
01456        fields contain the highlight information.  The action field
01457        is set to MULTILIST_ACTION_STATUS, and the item_index and string
01458        fields are invalid.
01459 
01460  *---------------------------------------------------------------------------*/
01461 
01462 XfwfMultiListReturnStruct *XfwfMultiListGetHighlighted(mlw)
01463 XfwfMultiListWidget mlw;
01464 {
01465        XfwfMultiListItem *item;
01466        static XfwfMultiListReturnStruct ret_value;
01467 
01468        ret_value.action = XfwfMultiListActionStatus;
01469        if (MultiListNumSelected(mlw) == 0)
01470        {
01471               ret_value.item = -1;
01472               ret_value.string = NULL;
01473        }
01474            else
01475        {
01476               ret_value.item = MultiListSelArray(mlw)
01477                      [MultiListNumSelected(mlw) - 1];
01478               item = MultiListNthItem(mlw,ret_value.item);
01479               ret_value.string = MultiListItemString(item);
01480        }
01481        ret_value.num_selected = MultiListNumSelected(mlw);
01482        ret_value.selected_items = MultiListSelArray(mlw);
01483        return(&ret_value);
01484 } /* End XfwfMultiListGetHighlighted */
01485 
01486 
01487 /*---------------------------------------------------------------------------*
01488 
01489        Boolean XfwfMultiListIsHighlighted(mlw,item_index)
01490 
01491        This routine checks if the item with index <item_index>
01492        is highlighted and returns True or False depending.  If
01493        <item_index> is invalid, False is returned.
01494 
01495  *---------------------------------------------------------------------------*/
01496 
01497 Boolean XfwfMultiListIsHighlighted(mlw,item_index)
01498 XfwfMultiListWidget mlw;
01499 int item_index;
01500 {
01501        XfwfMultiListItem *item;
01502 
01503        if (item_index < 0 || item_index >= MultiListNumItems(mlw))
01504               return(False);
01505        item = MultiListNthItem(mlw,item_index);
01506        return(MultiListItemHighlighted(item));
01507 } /* End XfwfMultiListIsHighlighted */
01508 
01509 
01510 /*---------------------------------------------------------------------------*
01511 
01512        Boolean XfwfMultiListGetItemInfo(mlw,item_index,str_ptr,h_ptr,s_ptr)
01513 
01514        This routine returns the string, highlight status and
01515        sensitivity information for the item with index <item_index>
01516        via the pointers <str_ptr>, <h_ptr> and <s_ptr>.  If the item
01517        index is invalid, False is returned, else True is returned.
01518 
01519  *---------------------------------------------------------------------------*/
01520 
01521 Boolean XfwfMultiListGetItemInfo(mlw,item_index,str_ptr,h_ptr,s_ptr)
01522 XfwfMultiListWidget mlw;
01523 int item_index;
01524 String *str_ptr;
01525 Boolean *h_ptr,*s_ptr;
01526 {
01527        XfwfMultiListItem *item;
01528 
01529        if (item_index < 0 || item_index >= MultiListNumItems(mlw))
01530               return(False);
01531        item = MultiListNthItem(mlw,item_index);
01532        *str_ptr = MultiListItemString(item);
01533        *h_ptr = MultiListItemHighlighted(item);
01534        *s_ptr = MultiListItemSensitive(item);
01535        return(True);
01536 } /* End XfwfMultiListGetItemInfo */
01537 
01538 
01539 /*---------------------------------------------------------------------------*
01540 
01541        XfwfMultiListSetNewData(mlw,list,nitems,longest,resize,
01542               sensitivity_array)
01543 
01544        This routine will set a new set of strings <list> into the
01545        MultiList widget <mlw>.  If <resize> is True, the MultiList widget will
01546        try to resize itself.
01547 
01548  *---------------------------------------------------------------------------*/
01549 
01550 #if NeedFunctionPrototypes
01551 void
01552 XfwfMultiListSetNewData(XfwfMultiListWidget mlw, String *list,
01553                      int nitems, int longest, Boolean resize,
01554                      Boolean *sensitivity_array)
01555 #else
01556 void
01557 XfwfMultiListSetNewData(mlw,list,nitems,longest,resize,sensitivity_array)
01558 XfwfMultiListWidget mlw;
01559 String *list;
01560 int nitems,longest;
01561 int resize;
01562 Boolean *sensitivity_array;
01563 #endif
01564 {
01565        DestroyOldData(mlw);
01566        MultiListList(mlw) = list;
01567        MultiListNumItems(mlw) = max(nitems,0);
01568        MultiListSensitiveArray(mlw) = sensitivity_array;
01569        MultiListNumCols(mlw) = 1;
01570        MultiListNumRows(mlw) = nitems;
01571 
01572        MultiListColWidth(mlw) = MultiListWidth(mlw);
01573         MultiListRowHeight(mlw) = FontH(MultiListFont(mlw), MultiListXftFont(mlw));
01574 
01575        if (MultiListNumItems(mlw) == 0) {
01576            MultiListList(mlw) = NULL;
01577            MultiListSensitiveArray(mlw) = NULL;
01578        }
01579        InitializeNewData(mlw);
01580        if (XtIsRealized((Widget)mlw)) Redisplay(mlw,NULL,NULL);
01581 } /* End XfwfMultiListSetNewData */