Copied the recent modifications of parse.y.
[nedit.git] / util / managedList.c
blob67eca8c324289290a7f8437b80c4698fbbfc5aff
1 static const char CVSID[] = "$Id: managedList.c,v 1.12 2003/05/02 19:19:03 edg Exp $";
2 /*******************************************************************************
3 * *
4 * managedList.c -- User interface for reorderable list of records *
5 * *
6 * Copyright (C) 1999 Mark Edel *
7 * *
8 * This is free software; you can redistribute it and/or modify it under the *
9 * terms of the GNU General Public License as published by the Free Software *
10 * Foundation; either version 2 of the License, or (at your option) any later *
11 * version. *
12 * *
13 * This software is distributed in the hope that it will be useful, but WITHOUT *
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
16 * for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License along with *
19 * software; if not, write to the Free Software Foundation, Inc., 59 Temple *
20 * Place, Suite 330, Boston, MA 02111-1307 USA *
21 * *
22 * Nirvana Text Editor *
23 * November, 1995 *
24 * *
25 * Written by Mark Edel *
26 * *
27 *******************************************************************************/
29 #ifdef HAVE_CONFIG_H
30 #include "../config.h"
31 #endif
33 #include "managedList.h"
34 #include "misc.h"
36 #include <stdio.h>
37 #include <string.h>
39 #include <X11/Intrinsic.h>
40 #include <Xm/Form.h>
41 #include <Xm/List.h>
42 #include <Xm/PushB.h>
43 #include <Xm/RowColumn.h>
45 #ifdef HAVE_DEBUG_H
46 #include "../debug.h"
47 #endif
49 /* Common data between the managed list callback functions */
50 typedef struct {
51 Widget listW, deleteBtn, copyBtn, moveUpBtn, moveDownBtn;
52 void *(*getDialogDataCB)(void *, int, int *, void *);
53 void *getDialogDataArg;
54 void (*setDialogDataCB)(void *, void *);
55 void *setDialogDataArg;
56 void *(*copyItemCB)(void *);
57 void (*freeItemCB)(void *);
58 int (*deleteConfirmCB)(int, void *);
59 void *deleteConfirmArg;
60 int maxItems;
61 int *nItems;
62 void **itemList;
63 int lastSelection;
64 } managedListData;
66 static void destroyCB(Widget w, XtPointer clientData, XtPointer callData);
67 static void deleteCB(Widget w, XtPointer clientData, XtPointer callData);
68 static void copyCB(Widget w, XtPointer clientData, XtPointer callData);
69 static void moveUpCB(Widget w, XtPointer clientData, XtPointer callData);
70 static void moveDownCB(Widget w, XtPointer clientData, XtPointer callData);
71 static int incorporateDialogData(managedListData *ml, int listPos,
72 int explicit);
73 static void updateDialogFromList(managedListData *ml, int selection);
74 static void updateListWidgetItem(managedListData *ml, int listPos);
75 static void listSelectionCB(Widget w, XtPointer clientData, XtPointer callData);
76 static int selectedListPosition(managedListData *ml);
77 static void selectItem(Widget listW, int itemIndex, int updateDialog);
80 ** Create a user interface to help manage a list of arbitrary data records
81 ** which users can edit, add, delete, and reorder.
83 ** The caller creates the overall dialog for presenting the data to the user,
84 ** but embeds the list and button widgets created here (and list management
85 ** code they activate) to handle the organization of the overall list.
87 ** This routine creates a form widget containing the buttons and list widget
88 ** with which the user interacts with the list data. ManageListAndButtons
89 ** can be used alternatively to take advantage of the management code with a
90 ** different arrangement of the widgets (this routine puts buttons in a
91 ** column on the left, list on the right) imposed here.
93 ** "args" and "argc" are passed to the form widget creation routine, so that
94 ** attachments can be specified for embedding the form in a dialog.
96 ** See ManageListAndButtons for a description of the remaining arguments.
98 Widget CreateManagedList(Widget parent, char *name, Arg *args,
99 int argC, void **itemList, int *nItems, int maxItems, int nColumns,
100 void *(*getDialogDataCB)(void *, int, int *, void *),
101 void *getDialogDataArg, void (*setDialogDataCB)(void *, void *),
102 void *setDialogDataArg, void (*freeItemCB)(void *))
104 int ac;
105 Arg al[20];
106 XmString s1;
107 Widget form, rowCol, listW;
108 Widget deleteBtn, copyBtn, moveUpBtn, moveDownBtn;
109 XmString *placeholderTable;
110 char *placeholderStr;
112 form = XmCreateForm(parent, name, args, argC);
113 XtManageChild(form);
114 rowCol = XtVaCreateManagedWidget("mlRowCol", xmRowColumnWidgetClass, form,
115 XmNpacking, XmPACK_COLUMN,
116 XmNleftAttachment, XmATTACH_FORM,
117 XmNtopAttachment, XmATTACH_FORM,
118 XmNbottomAttachment, XmATTACH_FORM, NULL);
119 deleteBtn = XtVaCreateManagedWidget("delete", xmPushButtonWidgetClass,
120 rowCol, XmNlabelString, s1=XmStringCreateSimple("Delete"), NULL);
121 XmStringFree(s1);
122 copyBtn = XtVaCreateManagedWidget("copy", xmPushButtonWidgetClass, rowCol,
123 XmNlabelString, s1=XmStringCreateSimple("Copy"), NULL);
124 XmStringFree(s1);
125 moveUpBtn = XtVaCreateManagedWidget("moveUp", xmPushButtonWidgetClass,
126 rowCol, XmNlabelString, s1=XmStringCreateSimple("Move ^"), NULL);
127 XmStringFree(s1);
128 moveDownBtn = XtVaCreateManagedWidget("moveDown", xmPushButtonWidgetClass,
129 rowCol, XmNlabelString, s1=XmStringCreateSimple("Move v"), NULL);
130 XmStringFree(s1);
132 /* AFAIK the only way to make a list widget n-columns wide is to make up
133 a fake initial string of that width, and create it with that */
134 placeholderStr = XtMalloc(nColumns+1);
135 memset(placeholderStr, 'm', nColumns);
136 placeholderStr[nColumns] = '\0';
137 placeholderTable = StringTable(1, placeholderStr);
138 XtFree(placeholderStr);
140 ac = 0;
141 XtSetArg(al[ac], XmNscrollBarDisplayPolicy, XmAS_NEEDED); ac++;
142 XtSetArg(al[ac], XmNlistSizePolicy, XmCONSTANT); ac++;
143 XtSetArg(al[ac], XmNitems, placeholderTable); ac++;
144 XtSetArg(al[ac], XmNitemCount, 1); ac++;
145 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
146 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
147 XtSetArg(al[ac], XmNleftWidget, rowCol); ac++;
148 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
149 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
150 listW = XmCreateScrolledList(form, "list", al, ac);
151 AddMouseWheelSupport(listW);
152 XtManageChild(listW);
153 FreeStringTable(placeholderTable);
155 return ManageListAndButtons(listW, deleteBtn, copyBtn, moveUpBtn,
156 moveDownBtn, itemList, nItems, maxItems, getDialogDataCB,
157 getDialogDataArg, setDialogDataCB, setDialogDataArg, freeItemCB);
161 ** Manage a list widget and a set of buttons which represent a list of
162 ** records. The caller provides facilities for editing the records
163 ** individually, and this code handles the organization of the overall list,
164 ** such that the user can modify, add, and delete records, and re-order the
165 ** list.
167 ** The format for the list of records managed by this code should be an
168 ** array of size "maxItems" of pointers to record structures. The records
169 ** themselves can be of any format, but the first field of the structure
170 ** must be a pointer to a character string which will be displayed as the
171 ** item name in the list. The list "itemList", and the number of items
172 ** "nItems" are automatically updated by the list management routines as the
173 ** user makes changes.
175 ** The caller must provide routines for transferring data to and from the
176 ** dialog fields dedicated to displaying and editing records in the list.
177 ** The callback "setDialogDataCB" must take the contents of the item pointer
178 ** passed to it, and display the data it contains, erasing any previously
179 ** displayed data. The format of the setDialogData callback is:
181 ** void setDialogDataCB(void *item, void *cbArg)
183 ** item: a pointer to the record to be displayed
185 ** cbArg: an arbitrary argument passed on to the callback routine
187 ** The callback "setDialogDataCB" must allocate (with XtMalloc) and return a
188 ** new record reflecting the current contents of the dialog fields. It may
189 ** do error checking on the data that the user has entered, and can abort
190 ** whatever operation triggered the request by setting "abort" to True.
191 ** This routine is called in a variety of contexts, such as the user
192 ** clicking on a list item, or requesting that a copy be made of the current
193 ** list item. To aide in communicating errors to the user, the boolean value
194 ** "explicitRequest" distinguishes between the case where the user has
195 ** specifically requested that the fields be read, and the case where he
196 ** may be surprised that errors are being reported, and require further
197 ** explanation. The format of the getDialogData callback is:
199 ** void *getDialogDataCB(void *oldItem, int explicitRequest, int *abort,
200 ** void *cbArg)
202 ** oldItem: a pointer to the existing record being modified in the
203 ** dialog, or NULL, if the user is modifying the "New" item.
205 ** explicitRequest: True if the user directly asked for the records
206 ** to be changed (as with an OK or Apply button). If a less direct
207 ** process resulted in the request, the user might need extra
208 ** explanation and possibly a chance to proceed using the existing
209 ** stored data (to use the data from oldItem, the routine should
210 ** make a new copy).
212 ** abort: Can be set to True if the dialog fields contain errors.
213 ** Setting abort to True, stops whetever process made the request
214 ** for updating the data in the list from the displayed data, and
215 ** forces the user to remain focused on the currently displayed
216 ** item until he either gives up or gets it right.
218 ** cbArg: arbitrary data, passed on from where the callback was
219 ** established in the list creation routines
221 ** The return value should be an allocated
223 ** The callback "freeItemCB" should free the item passed to it:
225 ** void freeItemCB(void *item, void *cbArg)
227 ** item: a pointer to the record to be freed
229 ** The difference between ManageListAndButtons and CreateManagedList, is that
230 ** in this routine, the caller creates the list and button widgets and passes
231 ** them here so that they be arranged explicitly, rather than relying on the
232 ** default style imposed by CreateManagedList. ManageListAndButtons simply
233 ** attaches the appropriate callbacks to process mouse and keyboard input from
234 ** the widgets.
236 Widget ManageListAndButtons(Widget listW, Widget deleteBtn, Widget copyBtn,
237 Widget moveUpBtn, Widget moveDownBtn, void **itemList, int *nItems,
238 int maxItems, void *(*getDialogDataCB)(void *, int, int *, void *),
239 void *getDialogDataArg, void (*setDialogDataCB)(void *, void *),
240 void *setDialogDataArg, void (*freeItemCB)(void *))
242 managedListData *ml;
244 /* Create a managedList data structure to hold information about the
245 widgets, callbacks, and current state of the list */
246 ml = (managedListData *)XtMalloc(sizeof(managedListData));
247 ml->listW = listW;
248 ml->deleteBtn = deleteBtn;
249 ml->copyBtn = copyBtn;
250 ml->moveUpBtn = moveUpBtn;
251 ml->moveDownBtn = moveDownBtn;
252 ml->getDialogDataCB = NULL;
253 ml->getDialogDataArg = setDialogDataArg;
254 ml->setDialogDataCB = NULL;
255 ml->setDialogDataArg = setDialogDataArg;
256 ml->freeItemCB = freeItemCB;
257 ml->deleteConfirmCB = NULL;
258 ml->deleteConfirmArg = NULL;
259 ml->nItems = nItems;
260 ml->maxItems = maxItems;
261 ml->itemList = itemList;
262 ml->lastSelection = 1;
264 /* Make the managed list data structure accessible from the list widget
265 pointer, and make sure it gets freed when the list is destroyed */
266 XtVaSetValues(ml->listW, XmNuserData, ml, NULL);
267 XtAddCallback(ml->listW, XmNdestroyCallback, destroyCB, ml);
269 /* Add callbacks for button and list actions */
270 XtAddCallback(ml->deleteBtn, XmNactivateCallback, deleteCB, ml);
271 XtAddCallback(ml->copyBtn, XmNactivateCallback, copyCB, ml);
272 XtAddCallback(ml->moveUpBtn, XmNactivateCallback, moveUpCB, ml);
273 XtAddCallback(ml->moveDownBtn, XmNactivateCallback, moveDownCB, ml);
274 XtAddCallback(ml->listW, XmNbrowseSelectionCallback, listSelectionCB, ml);
276 /* Initialize the list and buttons (don't set up the callbacks until
277 this is done, so they won't get called on creation) */
278 updateDialogFromList(ml, -1);
279 ml->getDialogDataCB = getDialogDataCB;
280 ml->setDialogDataCB = setDialogDataCB;
282 return ml->listW;
286 ** Update the currently selected list item from the dialog fields, using
287 ** the getDialogDataCB callback. "explicitRequest" is a boolean value
288 ** passed to on to the getDialogDataCB callback to help set the tone for
289 ** how error messages are presented (see ManageListAndButtons for more
290 ** information).
292 int UpdateManagedList(Widget listW, int explicitRequest)
294 managedListData *ml;
296 /* Recover the pointer to the managed list structure from the widget's
297 userData pointer */
298 XtVaGetValues(listW, XmNuserData, &ml, NULL);
300 /* Make the update */
301 return incorporateDialogData(ml, selectedListPosition(ml), explicitRequest);
305 ** Update the displayed list and data to agree with a data list which has
306 ** been changed externally (not by the ManagedList list manager).
308 void ChangeManagedListData(Widget listW)
310 managedListData *ml;
312 /* Recover the pointer to the managed list structure from the widget's
313 userData pointer */
314 XtVaGetValues(listW, XmNuserData, &ml, NULL);
316 updateDialogFromList(ml, -1);
320 ** Change the selected item in the managed list given the index into the
321 ** list being managed.
323 void SelectManagedListItem(Widget listW, int itemIndex)
325 selectItem(listW, itemIndex, True);
329 ** Return the index of the item currently selected in the list
331 int ManagedListSelectedIndex(Widget listW)
333 managedListData *ml;
335 XtVaGetValues(listW, XmNuserData, &ml, NULL);
336 return selectedListPosition(ml)-2;
340 ** Add a delete-confirmation callback to a managed list. This will be called
341 ** when the user presses the Delete button on the managed list. The callback
342 ** can put up a dialog, and optionally abort the operation by returning False.
344 void AddDeleteConfirmCB(Widget listW, int (*deleteConfirmCB)(int, void *),
345 void *deleteConfirmArg)
347 managedListData *ml;
349 XtVaGetValues(listW, XmNuserData, &ml, NULL);
350 ml->deleteConfirmCB = deleteConfirmCB;
351 ml->deleteConfirmArg = deleteConfirmArg;
355 ** Called on destruction of the list widget
357 static void destroyCB(Widget w, XtPointer clientData, XtPointer callData)
359 /* Free the managed list data structure */
360 XtFree((char *)clientData);
364 ** Button callbacks: deleteCB, copyCB, moveUpCB, moveDownCB
366 static void deleteCB(Widget w, XtPointer clientData, XtPointer callData)
368 managedListData *ml = (managedListData *)clientData;
369 int i, ind, listPos;
371 /* get the selected list position and the item to be deleted */
372 listPos = selectedListPosition(ml);
373 ind = listPos-2;
375 /* if there's a delete confirmation callback, call it first, and allow
376 it to request that the operation be aborted */
377 if (ml->deleteConfirmCB != NULL)
378 if (!(*ml->deleteConfirmCB)(ind, ml->deleteConfirmArg))
379 return;
381 /* free the item and remove it from the list */
382 (*ml->freeItemCB)(ml->itemList[ind]);
383 for (i=ind; i<*ml->nItems-1; i++)
384 ml->itemList[i] = ml->itemList[i+1];
385 (*ml->nItems)--;
387 /* update the list widget and move the selection to the previous item
388 in the list and display the fields appropriate for that entry */
389 updateDialogFromList(ml, ind-1);
392 static void copyCB(Widget w, XtPointer clientData, XtPointer callData)
394 managedListData *ml = (managedListData *)clientData;
395 int i, listPos, abort = False;
396 void *item;
398 /* get the selected list position and the item to be copied */
399 listPos = selectedListPosition(ml);
400 if (listPos == 1)
401 return; /* can't copy "new" */
403 /* Bring the entry up to date (could result in operation being canceled) */
404 item = (*ml->getDialogDataCB)(ml->itemList[listPos-2], False, &abort,
405 ml->getDialogDataArg);
406 if (abort)
407 return;
408 if (item != NULL) {
409 (*ml->freeItemCB)(ml->itemList[listPos-2]);
410 ml->itemList[listPos-2] = item;
413 /* Make a copy by requesting the data again.
414 In case getDialogDataCB() returned a fallback value, the dialog may
415 not be in sync with the internal list. If we _explicitly_ request the
416 data again, we could get an invalid answer. Therefore, we first update
417 the dialog to make sure that we can copy the right data. */
418 updateDialogFromList(ml, listPos-2);
419 item = (*ml->getDialogDataCB)(ml->itemList[listPos-2], True, &abort,
420 ml->getDialogDataArg);
421 if (abort)
422 return;
424 /* add the item to the item list */
425 for (i= *ml->nItems; i>=listPos; i--)
426 ml->itemList[i] = ml->itemList[i-1];
427 ml->itemList[listPos-1] = item;
428 (*ml->nItems)++;
430 /* redisplay the list widget and select the new item */
431 updateDialogFromList(ml, listPos-1);
434 static void moveUpCB(Widget w, XtPointer clientData, XtPointer callData)
436 managedListData *ml = (managedListData *)clientData;
437 int ind, listPos;
438 void *temp;
440 /* get the item index currently selected in the menu item list */
441 listPos = selectedListPosition(ml);
442 ind = listPos-2;
444 /* Bring the item up to date with the dialog fields (It would be better
445 if this could be avoided, because user errors will be flagged here,
446 but it's not worth re-writing everything for such a trivial point) */
447 if (!incorporateDialogData(ml, ml->lastSelection, False))
448 return;
450 /* shuffle the item up in the menu item list */
451 temp = ml->itemList[ind];
452 ml->itemList[ind] = ml->itemList[ind-1];
453 ml->itemList[ind-1] = temp;
455 /* update the list widget and keep the selection on moved item */
456 updateDialogFromList(ml, ind-1);
459 static void moveDownCB(Widget w, XtPointer clientData, XtPointer callData)
461 managedListData *ml = (managedListData *)clientData;
462 int ind, listPos;
463 void *temp;
465 /* get the item index currently selected in the menu item list */
466 listPos = selectedListPosition(ml);
467 ind = listPos-2;
469 /* Bring the item up to date with the dialog fields (I wish this could
470 be avoided) */
471 if (!incorporateDialogData(ml, ml->lastSelection, False))
472 return;
474 /* shuffle the item down in the menu item list */
475 temp = ml->itemList[ind];
476 ml->itemList[ind] = ml->itemList[ind+1];
477 ml->itemList[ind+1] = temp;
479 /* update the list widget and keep the selection on moved item */
480 updateDialogFromList(ml, ind+1);
484 ** Called when the user clicks on an item in the list widget
486 static void listSelectionCB(Widget w, XtPointer clientData, XtPointer callData)
488 managedListData *ml = (managedListData *)clientData;
489 int ind, listPos = ((XmListCallbackStruct *)callData)->item_position;
491 /* Save the current dialog fields before overwriting them. If there's an
492 error, force the user to go back to the old selection and fix it
493 before proceeding */
494 if (ml->getDialogDataCB != NULL && ml->lastSelection != 0) {
495 if (!incorporateDialogData(ml, ml->lastSelection, False)) {
496 XmListDeselectAllItems(ml->listW);
497 XmListSelectPos(ml->listW, ml->lastSelection, False);
498 return;
500 /* reselect item because incorporateDialogData can alter selection */
501 selectItem(ml->listW, listPos-2, False);
503 ml->lastSelection = listPos;
505 /* Dim or un-dim buttons at bottom of dialog based on whether the
506 selected item is a menu entry, or "New" */
507 if (listPos == 1) {
508 XtSetSensitive(ml->copyBtn, False);
509 XtSetSensitive(ml->deleteBtn, False);
510 XtSetSensitive(ml->moveUpBtn, False);
511 XtSetSensitive(ml->moveDownBtn, False);
512 } else {
513 XtSetSensitive(ml->copyBtn, True);
514 XtSetSensitive(ml->deleteBtn, True);
515 XtSetSensitive(ml->moveUpBtn, listPos != 2);
516 XtSetSensitive(ml->moveDownBtn, listPos != *ml->nItems+1);
519 /* get the index of the item currently selected in the item list */
520 ind = listPos - 2;
522 /* tell the caller to show the new item */
523 if (ml->setDialogDataCB != NULL)
524 (*ml->setDialogDataCB)(listPos==1 ? NULL : ml->itemList[ind],
525 ml->setDialogDataArg);
529 ** Incorporate the current contents of the dialog fields into the list
530 ** being managed, and if necessary change the display in the list widget.
531 ** The data is obtained by calling the getDialogDataCB callback, which
532 ** is allowed to reject whatever request triggered the update. If the
533 ** request is rejected, the return value from this function will be False.
535 static int incorporateDialogData(managedListData *ml, int listPos, int explicit)
537 int abort = False;
538 void *item;
540 /* Get the current contents of the dialog fields. Callback will set
541 abort to True if canceled */
542 item = (*ml->getDialogDataCB)(listPos == 1 ? NULL : ml->itemList[
543 listPos-2], explicit, &abort, ml->getDialogDataArg);
544 if (abort)
545 return False;
546 if (item == NULL) /* don't modify if fields are empty */
547 return True;
549 /* If the item is "new" add a new entry to the list, otherwise,
550 modify the entry with the text fields from the dialog */
551 if (listPos == 1) {
552 ml->itemList[(*ml->nItems)++] = item;
553 updateDialogFromList(ml, *ml->nItems - 1);
554 } else {
555 (*ml->freeItemCB)(ml->itemList[listPos-2]);
556 ml->itemList[listPos-2] = item;
557 updateListWidgetItem(ml, listPos);
559 return True;
563 ** Update the list widget to reflect the current contents of the managed item
564 ** list, set the item that should now be highlighted, and call getDisplayed
565 ** on the newly selected item to fill in the dialog fields.
567 static void updateDialogFromList(managedListData *ml, int selection)
569 int i;
570 XmString *stringTable;
572 /* On many systems under Motif 1.1 the list widget can't handle items
573 being changed while anything is selected! */
574 XmListDeselectAllItems(ml->listW);
576 /* Fill in the list widget with the names from the item list */
577 stringTable = (XmString *)XtMalloc(sizeof(XmString) * (*ml->nItems+1));
578 stringTable[0] = XmStringCreateSimple("New");
579 for (i=0; i < *ml->nItems; i++)
580 stringTable[i+1] = XmStringCreateSimple(*(char **)ml->itemList[i]);
581 XtVaSetValues(ml->listW, XmNitems, stringTable,
582 XmNitemCount, *ml->nItems+1, NULL);
583 for (i=0; i < *ml->nItems+1; i++)
584 XmStringFree(stringTable[i]);
585 XtFree((char *)stringTable);
587 /* Select the requested item (indirectly filling in the dialog fields),
588 but don't trigger an update of the last selected item from the current
589 dialog fields */
590 ml->lastSelection = 0;
591 selectItem(ml->listW, selection, True);
595 ** Update one item of the managed list widget to reflect the current contents
596 ** of the managed item list.
598 static void updateListWidgetItem(managedListData *ml, int listPos)
600 int savedPos;
601 XmString newString[1];
603 /* save the current selected position (Motif sometimes does stupid things
604 to the selection when a change is made, like selecting the new item
605 if it matches the name of currently selected one) */
606 savedPos = selectedListPosition(ml);
607 XmListDeselectAllItems(ml->listW);
609 /* update the list */
610 newString[0] = XmStringCreateSimple(*(char **)ml->itemList[listPos-2]);
611 XmListReplaceItemsPos(ml->listW, newString, 1, listPos);
612 XmStringFree(newString[0]);
614 /* restore the selected position */
615 XmListSelectPos(ml->listW, savedPos, False);
619 ** Get the position of the selection in the menu item list widget
621 static int selectedListPosition(managedListData *ml)
623 int listPos;
624 int *posList = NULL, posCount = 0;
626 if (!XmListGetSelectedPos(ml->listW, &posList, &posCount)) {
627 fprintf(stderr, "Internal error (nothing selected)");
628 return 1;
630 listPos = *posList;
631 XtFree((char *)posList);
632 if (listPos < 1 || listPos > *ml->nItems+1) {
633 fprintf(stderr, "Internal error (XmList bad value)");
634 return 1;
636 return listPos;
640 ** Select an item in the list given the list (array) index value.
641 ** If updateDialog is True, trigger a complete dialog update, which
642 ** could potentially reject the change.
644 static void selectItem(Widget listW, int itemIndex, int updateDialog)
646 int topPos, nVisible, selection = itemIndex+2;
648 /* Select the item */
649 XmListDeselectAllItems(listW);
650 XmListSelectPos(listW, selection, updateDialog);
652 /* If the selected item is not visible, scroll the list */
653 XtVaGetValues(listW, XmNtopItemPosition, &topPos, XmNvisibleItemCount,
654 &nVisible, NULL);
655 if (selection < topPos)
656 XmListSetPos(listW, selection);
657 else if (selection >= topPos + nVisible)
658 XmListSetPos(listW, selection - nVisible + 1);