Fix for SF bug #999021 Using exit() in a macro causes hang.
[nedit.git] / util / managedList.c
blob9a319b8a2b51e6fa185ab75a27ab2a0d3d7d156b
1 static const char CVSID[] = "$Id: managedList.c,v 1.14 2004/07/21 11:32:07 yooden 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. In addition, you may distribute version of this program linked to *
12 * Motif or Open Motif. See README for details. *
13 * *
14 * This software is distributed in the hope that it will be useful, but WITHOUT *
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
17 * for more details. *
18 * *
19 * You should have received a copy of the GNU General Public License along with *
20 * software; if not, write to the Free Software Foundation, Inc., 59 Temple *
21 * Place, Suite 330, Boston, MA 02111-1307 USA *
22 * *
23 * Nirvana Text Editor *
24 * November, 1995 *
25 * *
26 * Written by Mark Edel *
27 * *
28 *******************************************************************************/
30 #ifdef HAVE_CONFIG_H
31 #include "../config.h"
32 #endif
34 #include "managedList.h"
35 #include "misc.h"
37 #include <stdio.h>
38 #include <string.h>
40 #include <X11/Intrinsic.h>
41 #include <Xm/Form.h>
42 #include <Xm/List.h>
43 #include <Xm/PushB.h>
44 #include <Xm/RowColumn.h>
46 #ifdef HAVE_DEBUG_H
47 #include "../debug.h"
48 #endif
50 /* Common data between the managed list callback functions */
51 typedef struct {
52 Widget listW, deleteBtn, copyBtn, moveUpBtn, moveDownBtn;
53 void *(*getDialogDataCB)(void *, int, int *, void *);
54 void *getDialogDataArg;
55 void (*setDialogDataCB)(void *, void *);
56 void *setDialogDataArg;
57 void *(*copyItemCB)(void *);
58 void (*freeItemCB)(void *);
59 int (*deleteConfirmCB)(int, void *);
60 void *deleteConfirmArg;
61 int maxItems;
62 int *nItems;
63 void **itemList;
64 int lastSelection;
65 } managedListData;
67 static void destroyCB(Widget w, XtPointer clientData, XtPointer callData);
68 static void deleteCB(Widget w, XtPointer clientData, XtPointer callData);
69 static void copyCB(Widget w, XtPointer clientData, XtPointer callData);
70 static void moveUpCB(Widget w, XtPointer clientData, XtPointer callData);
71 static void moveDownCB(Widget w, XtPointer clientData, XtPointer callData);
72 static int incorporateDialogData(managedListData *ml, int listPos,
73 int explicit);
74 static void updateDialogFromList(managedListData *ml, int selection);
75 static void updateListWidgetItem(managedListData *ml, int listPos);
76 static void listSelectionCB(Widget w, XtPointer clientData, XtPointer callData);
77 static int selectedListPosition(managedListData *ml);
78 static void selectItem(Widget listW, int itemIndex, int updateDialog);
81 ** Create a user interface to help manage a list of arbitrary data records
82 ** which users can edit, add, delete, and reorder.
84 ** The caller creates the overall dialog for presenting the data to the user,
85 ** but embeds the list and button widgets created here (and list management
86 ** code they activate) to handle the organization of the overall list.
88 ** This routine creates a form widget containing the buttons and list widget
89 ** with which the user interacts with the list data. ManageListAndButtons
90 ** can be used alternatively to take advantage of the management code with a
91 ** different arrangement of the widgets (this routine puts buttons in a
92 ** column on the left, list on the right) imposed here.
94 ** "args" and "argc" are passed to the form widget creation routine, so that
95 ** attachments can be specified for embedding the form in a dialog.
97 ** See ManageListAndButtons for a description of the remaining arguments.
99 Widget CreateManagedList(Widget parent, char *name, Arg *args,
100 int argC, void **itemList, int *nItems, int maxItems, int nColumns,
101 void *(*getDialogDataCB)(void *, int, int *, void *),
102 void *getDialogDataArg, void (*setDialogDataCB)(void *, void *),
103 void *setDialogDataArg, void (*freeItemCB)(void *))
105 int ac;
106 Arg al[20];
107 XmString s1;
108 Widget form, rowCol, listW;
109 Widget deleteBtn, copyBtn, moveUpBtn, moveDownBtn;
110 XmString *placeholderTable;
111 char *placeholderStr;
113 form = XmCreateForm(parent, name, args, argC);
114 XtManageChild(form);
115 rowCol = XtVaCreateManagedWidget("mlRowCol", xmRowColumnWidgetClass, form,
116 XmNpacking, XmPACK_COLUMN,
117 XmNleftAttachment, XmATTACH_FORM,
118 XmNtopAttachment, XmATTACH_FORM,
119 XmNbottomAttachment, XmATTACH_FORM, NULL);
120 deleteBtn = XtVaCreateManagedWidget("delete", xmPushButtonWidgetClass,
121 rowCol, XmNlabelString, s1=XmStringCreateSimple("Delete"), NULL);
122 XmStringFree(s1);
123 copyBtn = XtVaCreateManagedWidget("copy", xmPushButtonWidgetClass, rowCol,
124 XmNlabelString, s1=XmStringCreateSimple("Copy"), NULL);
125 XmStringFree(s1);
126 moveUpBtn = XtVaCreateManagedWidget("moveUp", xmPushButtonWidgetClass,
127 rowCol, XmNlabelString, s1=XmStringCreateSimple("Move ^"), NULL);
128 XmStringFree(s1);
129 moveDownBtn = XtVaCreateManagedWidget("moveDown", xmPushButtonWidgetClass,
130 rowCol, XmNlabelString, s1=XmStringCreateSimple("Move v"), NULL);
131 XmStringFree(s1);
133 /* AFAIK the only way to make a list widget n-columns wide is to make up
134 a fake initial string of that width, and create it with that */
135 placeholderStr = XtMalloc(nColumns+1);
136 memset(placeholderStr, 'm', nColumns);
137 placeholderStr[nColumns] = '\0';
138 placeholderTable = StringTable(1, placeholderStr);
139 XtFree(placeholderStr);
141 ac = 0;
142 XtSetArg(al[ac], XmNscrollBarDisplayPolicy, XmAS_NEEDED); ac++;
143 XtSetArg(al[ac], XmNlistSizePolicy, XmCONSTANT); ac++;
144 XtSetArg(al[ac], XmNitems, placeholderTable); ac++;
145 XtSetArg(al[ac], XmNitemCount, 1); ac++;
146 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
147 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
148 XtSetArg(al[ac], XmNleftWidget, rowCol); ac++;
149 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
150 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
151 listW = XmCreateScrolledList(form, "list", al, ac);
152 AddMouseWheelSupport(listW);
153 XtManageChild(listW);
154 FreeStringTable(placeholderTable);
156 return ManageListAndButtons(listW, deleteBtn, copyBtn, moveUpBtn,
157 moveDownBtn, itemList, nItems, maxItems, getDialogDataCB,
158 getDialogDataArg, setDialogDataCB, setDialogDataArg, freeItemCB);
162 ** Manage a list widget and a set of buttons which represent a list of
163 ** records. The caller provides facilities for editing the records
164 ** individually, and this code handles the organization of the overall list,
165 ** such that the user can modify, add, and delete records, and re-order the
166 ** list.
168 ** The format for the list of records managed by this code should be an
169 ** array of size "maxItems" of pointers to record structures. The records
170 ** themselves can be of any format, but the first field of the structure
171 ** must be a pointer to a character string which will be displayed as the
172 ** item name in the list. The list "itemList", and the number of items
173 ** "nItems" are automatically updated by the list management routines as the
174 ** user makes changes.
176 ** The caller must provide routines for transferring data to and from the
177 ** dialog fields dedicated to displaying and editing records in the list.
178 ** The callback "setDialogDataCB" must take the contents of the item pointer
179 ** passed to it, and display the data it contains, erasing any previously
180 ** displayed data. The format of the setDialogData callback is:
182 ** void setDialogDataCB(void *item, void *cbArg)
184 ** item: a pointer to the record to be displayed
186 ** cbArg: an arbitrary argument passed on to the callback routine
188 ** The callback "setDialogDataCB" must allocate (with XtMalloc) and return a
189 ** new record reflecting the current contents of the dialog fields. It may
190 ** do error checking on the data that the user has entered, and can abort
191 ** whatever operation triggered the request by setting "abort" to True.
192 ** This routine is called in a variety of contexts, such as the user
193 ** clicking on a list item, or requesting that a copy be made of the current
194 ** list item. To aide in communicating errors to the user, the boolean value
195 ** "explicitRequest" distinguishes between the case where the user has
196 ** specifically requested that the fields be read, and the case where he
197 ** may be surprised that errors are being reported, and require further
198 ** explanation. The format of the getDialogData callback is:
200 ** void *getDialogDataCB(void *oldItem, int explicitRequest, int *abort,
201 ** void *cbArg)
203 ** oldItem: a pointer to the existing record being modified in the
204 ** dialog, or NULL, if the user is modifying the "New" item.
206 ** explicitRequest: True if the user directly asked for the records
207 ** to be changed (as with an OK or Apply button). If a less direct
208 ** process resulted in the request, the user might need extra
209 ** explanation and possibly a chance to proceed using the existing
210 ** stored data (to use the data from oldItem, the routine should
211 ** make a new copy).
213 ** abort: Can be set to True if the dialog fields contain errors.
214 ** Setting abort to True, stops whetever process made the request
215 ** for updating the data in the list from the displayed data, and
216 ** forces the user to remain focused on the currently displayed
217 ** item until he either gives up or gets it right.
219 ** cbArg: arbitrary data, passed on from where the callback was
220 ** established in the list creation routines
222 ** The return value should be an allocated
224 ** The callback "freeItemCB" should free the item passed to it:
226 ** void freeItemCB(void *item, void *cbArg)
228 ** item: a pointer to the record to be freed
230 ** The difference between ManageListAndButtons and CreateManagedList, is that
231 ** in this routine, the caller creates the list and button widgets and passes
232 ** them here so that they be arranged explicitly, rather than relying on the
233 ** default style imposed by CreateManagedList. ManageListAndButtons simply
234 ** attaches the appropriate callbacks to process mouse and keyboard input from
235 ** the widgets.
237 Widget ManageListAndButtons(Widget listW, Widget deleteBtn, Widget copyBtn,
238 Widget moveUpBtn, Widget moveDownBtn, void **itemList, int *nItems,
239 int maxItems, void *(*getDialogDataCB)(void *, int, int *, void *),
240 void *getDialogDataArg, void (*setDialogDataCB)(void *, void *),
241 void *setDialogDataArg, void (*freeItemCB)(void *))
243 managedListData *ml;
245 /* Create a managedList data structure to hold information about the
246 widgets, callbacks, and current state of the list */
247 ml = (managedListData *)XtMalloc(sizeof(managedListData));
248 ml->listW = listW;
249 ml->deleteBtn = deleteBtn;
250 ml->copyBtn = copyBtn;
251 ml->moveUpBtn = moveUpBtn;
252 ml->moveDownBtn = moveDownBtn;
253 ml->getDialogDataCB = NULL;
254 ml->getDialogDataArg = getDialogDataArg;
255 ml->setDialogDataCB = NULL;
256 ml->setDialogDataArg = setDialogDataArg;
257 ml->freeItemCB = freeItemCB;
258 ml->deleteConfirmCB = NULL;
259 ml->deleteConfirmArg = NULL;
260 ml->nItems = nItems;
261 ml->maxItems = maxItems;
262 ml->itemList = itemList;
263 ml->lastSelection = 1;
265 /* Make the managed list data structure accessible from the list widget
266 pointer, and make sure it gets freed when the list is destroyed */
267 XtVaSetValues(ml->listW, XmNuserData, ml, NULL);
268 XtAddCallback(ml->listW, XmNdestroyCallback, destroyCB, ml);
270 /* Add callbacks for button and list actions */
271 XtAddCallback(ml->deleteBtn, XmNactivateCallback, deleteCB, ml);
272 XtAddCallback(ml->copyBtn, XmNactivateCallback, copyCB, ml);
273 XtAddCallback(ml->moveUpBtn, XmNactivateCallback, moveUpCB, ml);
274 XtAddCallback(ml->moveDownBtn, XmNactivateCallback, moveDownCB, ml);
275 XtAddCallback(ml->listW, XmNbrowseSelectionCallback, listSelectionCB, ml);
277 /* Initialize the list and buttons (don't set up the callbacks until
278 this is done, so they won't get called on creation) */
279 updateDialogFromList(ml, -1);
280 ml->getDialogDataCB = getDialogDataCB;
281 ml->setDialogDataCB = setDialogDataCB;
283 return ml->listW;
287 ** Update the currently selected list item from the dialog fields, using
288 ** the getDialogDataCB callback. "explicitRequest" is a boolean value
289 ** passed to on to the getDialogDataCB callback to help set the tone for
290 ** how error messages are presented (see ManageListAndButtons for more
291 ** information).
293 int UpdateManagedList(Widget listW, int explicitRequest)
295 managedListData *ml;
297 /* Recover the pointer to the managed list structure from the widget's
298 userData pointer */
299 XtVaGetValues(listW, XmNuserData, &ml, NULL);
301 /* Make the update */
302 return incorporateDialogData(ml, selectedListPosition(ml), explicitRequest);
306 ** Update the displayed list and data to agree with a data list which has
307 ** been changed externally (not by the ManagedList list manager).
309 void ChangeManagedListData(Widget listW)
311 managedListData *ml;
313 /* Recover the pointer to the managed list structure from the widget's
314 userData pointer */
315 XtVaGetValues(listW, XmNuserData, &ml, NULL);
317 updateDialogFromList(ml, -1);
321 ** Change the selected item in the managed list given the index into the
322 ** list being managed.
324 void SelectManagedListItem(Widget listW, int itemIndex)
326 selectItem(listW, itemIndex, True);
330 ** Return the index of the item currently selected in the list
332 int ManagedListSelectedIndex(Widget listW)
334 managedListData *ml;
336 XtVaGetValues(listW, XmNuserData, &ml, NULL);
337 return selectedListPosition(ml)-2;
341 ** Add a delete-confirmation callback to a managed list. This will be called
342 ** when the user presses the Delete button on the managed list. The callback
343 ** can put up a dialog, and optionally abort the operation by returning False.
345 void AddDeleteConfirmCB(Widget listW, int (*deleteConfirmCB)(int, void *),
346 void *deleteConfirmArg)
348 managedListData *ml;
350 XtVaGetValues(listW, XmNuserData, &ml, NULL);
351 ml->deleteConfirmCB = deleteConfirmCB;
352 ml->deleteConfirmArg = deleteConfirmArg;
356 ** Called on destruction of the list widget
358 static void destroyCB(Widget w, XtPointer clientData, XtPointer callData)
360 /* Free the managed list data structure */
361 XtFree((char *)clientData);
365 ** Button callbacks: deleteCB, copyCB, moveUpCB, moveDownCB
367 static void deleteCB(Widget w, XtPointer clientData, XtPointer callData)
369 managedListData *ml = (managedListData *)clientData;
370 int i, ind, listPos;
372 /* get the selected list position and the item to be deleted */
373 listPos = selectedListPosition(ml);
374 ind = listPos-2;
376 /* if there's a delete confirmation callback, call it first, and allow
377 it to request that the operation be aborted */
378 if (ml->deleteConfirmCB != NULL)
379 if (!(*ml->deleteConfirmCB)(ind, ml->deleteConfirmArg))
380 return;
382 /* free the item and remove it from the list */
383 (*ml->freeItemCB)(ml->itemList[ind]);
384 for (i=ind; i<*ml->nItems-1; i++)
385 ml->itemList[i] = ml->itemList[i+1];
386 (*ml->nItems)--;
388 /* update the list widget and move the selection to the previous item
389 in the list and display the fields appropriate for that entry */
390 updateDialogFromList(ml, ind-1);
393 static void copyCB(Widget w, XtPointer clientData, XtPointer callData)
395 managedListData *ml = (managedListData *)clientData;
396 int i, listPos, abort = False;
397 void *item;
399 /* get the selected list position and the item to be copied */
400 listPos = selectedListPosition(ml);
401 if (listPos == 1)
402 return; /* can't copy "new" */
404 /* Bring the entry up to date (could result in operation being canceled) */
405 item = (*ml->getDialogDataCB)(ml->itemList[listPos-2], False, &abort,
406 ml->getDialogDataArg);
407 if (abort)
408 return;
409 if (item != NULL) {
410 (*ml->freeItemCB)(ml->itemList[listPos-2]);
411 ml->itemList[listPos-2] = item;
414 /* Make a copy by requesting the data again.
415 In case getDialogDataCB() returned a fallback value, the dialog may
416 not be in sync with the internal list. If we _explicitly_ request the
417 data again, we could get an invalid answer. Therefore, we first update
418 the dialog to make sure that we can copy the right data. */
419 updateDialogFromList(ml, listPos-2);
420 item = (*ml->getDialogDataCB)(ml->itemList[listPos-2], True, &abort,
421 ml->getDialogDataArg);
422 if (abort)
423 return;
425 /* add the item to the item list */
426 for (i= *ml->nItems; i>=listPos; i--)
427 ml->itemList[i] = ml->itemList[i-1];
428 ml->itemList[listPos-1] = item;
429 (*ml->nItems)++;
431 /* redisplay the list widget and select the new item */
432 updateDialogFromList(ml, listPos-1);
435 static void moveUpCB(Widget w, XtPointer clientData, XtPointer callData)
437 managedListData *ml = (managedListData *)clientData;
438 int ind, listPos;
439 void *temp;
441 /* get the item index currently selected in the menu item list */
442 listPos = selectedListPosition(ml);
443 ind = listPos-2;
445 /* Bring the item up to date with the dialog fields (It would be better
446 if this could be avoided, because user errors will be flagged here,
447 but it's not worth re-writing everything for such a trivial point) */
448 if (!incorporateDialogData(ml, ml->lastSelection, False))
449 return;
451 /* shuffle the item up in the menu item list */
452 temp = ml->itemList[ind];
453 ml->itemList[ind] = ml->itemList[ind-1];
454 ml->itemList[ind-1] = temp;
456 /* update the list widget and keep the selection on moved item */
457 updateDialogFromList(ml, ind-1);
460 static void moveDownCB(Widget w, XtPointer clientData, XtPointer callData)
462 managedListData *ml = (managedListData *)clientData;
463 int ind, listPos;
464 void *temp;
466 /* get the item index currently selected in the menu item list */
467 listPos = selectedListPosition(ml);
468 ind = listPos-2;
470 /* Bring the item up to date with the dialog fields (I wish this could
471 be avoided) */
472 if (!incorporateDialogData(ml, ml->lastSelection, False))
473 return;
475 /* shuffle the item down in the menu item list */
476 temp = ml->itemList[ind];
477 ml->itemList[ind] = ml->itemList[ind+1];
478 ml->itemList[ind+1] = temp;
480 /* update the list widget and keep the selection on moved item */
481 updateDialogFromList(ml, ind+1);
485 ** Called when the user clicks on an item in the list widget
487 static void listSelectionCB(Widget w, XtPointer clientData, XtPointer callData)
489 managedListData *ml = (managedListData *)clientData;
490 int ind, listPos = ((XmListCallbackStruct *)callData)->item_position;
492 /* Save the current dialog fields before overwriting them. If there's an
493 error, force the user to go back to the old selection and fix it
494 before proceeding */
495 if (ml->getDialogDataCB != NULL && ml->lastSelection != 0) {
496 if (!incorporateDialogData(ml, ml->lastSelection, False)) {
497 XmListDeselectAllItems(ml->listW);
498 XmListSelectPos(ml->listW, ml->lastSelection, False);
499 return;
501 /* reselect item because incorporateDialogData can alter selection */
502 selectItem(ml->listW, listPos-2, False);
504 ml->lastSelection = listPos;
506 /* Dim or un-dim buttons at bottom of dialog based on whether the
507 selected item is a menu entry, or "New" */
508 if (listPos == 1) {
509 XtSetSensitive(ml->copyBtn, False);
510 XtSetSensitive(ml->deleteBtn, False);
511 XtSetSensitive(ml->moveUpBtn, False);
512 XtSetSensitive(ml->moveDownBtn, False);
513 } else {
514 XtSetSensitive(ml->copyBtn, True);
515 XtSetSensitive(ml->deleteBtn, True);
516 XtSetSensitive(ml->moveUpBtn, listPos != 2);
517 XtSetSensitive(ml->moveDownBtn, listPos != *ml->nItems+1);
520 /* get the index of the item currently selected in the item list */
521 ind = listPos - 2;
523 /* tell the caller to show the new item */
524 if (ml->setDialogDataCB != NULL)
525 (*ml->setDialogDataCB)(listPos==1 ? NULL : ml->itemList[ind],
526 ml->setDialogDataArg);
530 ** Incorporate the current contents of the dialog fields into the list
531 ** being managed, and if necessary change the display in the list widget.
532 ** The data is obtained by calling the getDialogDataCB callback, which
533 ** is allowed to reject whatever request triggered the update. If the
534 ** request is rejected, the return value from this function will be False.
536 static int incorporateDialogData(managedListData *ml, int listPos, int explicit)
538 int abort = False;
539 void *item;
541 /* Get the current contents of the dialog fields. Callback will set
542 abort to True if canceled */
543 item = (*ml->getDialogDataCB)(listPos == 1 ? NULL : ml->itemList[
544 listPos-2], explicit, &abort, ml->getDialogDataArg);
545 if (abort)
546 return False;
547 if (item == NULL) /* don't modify if fields are empty */
548 return True;
550 /* If the item is "new" add a new entry to the list, otherwise,
551 modify the entry with the text fields from the dialog */
552 if (listPos == 1) {
553 ml->itemList[(*ml->nItems)++] = item;
554 updateDialogFromList(ml, *ml->nItems - 1);
555 } else {
556 (*ml->freeItemCB)(ml->itemList[listPos-2]);
557 ml->itemList[listPos-2] = item;
558 updateListWidgetItem(ml, listPos);
560 return True;
564 ** Update the list widget to reflect the current contents of the managed item
565 ** list, set the item that should now be highlighted, and call getDisplayed
566 ** on the newly selected item to fill in the dialog fields.
568 static void updateDialogFromList(managedListData *ml, int selection)
570 int i;
571 XmString *stringTable;
573 /* On many systems under Motif 1.1 the list widget can't handle items
574 being changed while anything is selected! */
575 XmListDeselectAllItems(ml->listW);
577 /* Fill in the list widget with the names from the item list */
578 stringTable = (XmString *)XtMalloc(sizeof(XmString) * (*ml->nItems+1));
579 stringTable[0] = XmStringCreateSimple("New");
580 for (i=0; i < *ml->nItems; i++)
581 stringTable[i+1] = XmStringCreateSimple(*(char **)ml->itemList[i]);
582 XtVaSetValues(ml->listW, XmNitems, stringTable,
583 XmNitemCount, *ml->nItems+1, NULL);
584 for (i=0; i < *ml->nItems+1; i++)
585 XmStringFree(stringTable[i]);
586 XtFree((char *)stringTable);
588 /* Select the requested item (indirectly filling in the dialog fields),
589 but don't trigger an update of the last selected item from the current
590 dialog fields */
591 ml->lastSelection = 0;
592 selectItem(ml->listW, selection, True);
596 ** Update one item of the managed list widget to reflect the current contents
597 ** of the managed item list.
599 static void updateListWidgetItem(managedListData *ml, int listPos)
601 int savedPos;
602 XmString newString[1];
604 /* save the current selected position (Motif sometimes does stupid things
605 to the selection when a change is made, like selecting the new item
606 if it matches the name of currently selected one) */
607 savedPos = selectedListPosition(ml);
608 XmListDeselectAllItems(ml->listW);
610 /* update the list */
611 newString[0] = XmStringCreateSimple(*(char **)ml->itemList[listPos-2]);
612 XmListReplaceItemsPos(ml->listW, newString, 1, listPos);
613 XmStringFree(newString[0]);
615 /* restore the selected position */
616 XmListSelectPos(ml->listW, savedPos, False);
620 ** Get the position of the selection in the menu item list widget
622 static int selectedListPosition(managedListData *ml)
624 int listPos;
625 int *posList = NULL, posCount = 0;
627 if (!XmListGetSelectedPos(ml->listW, &posList, &posCount)) {
628 fprintf(stderr, "Internal error (nothing selected)");
629 return 1;
631 listPos = *posList;
632 XtFree((char *)posList);
633 if (listPos < 1 || listPos > *ml->nItems+1) {
634 fprintf(stderr, "Internal error (XmList bad value)");
635 return 1;
637 return listPos;
641 ** Select an item in the list given the list (array) index value.
642 ** If updateDialog is True, trigger a complete dialog update, which
643 ** could potentially reject the change.
645 static void selectItem(Widget listW, int itemIndex, int updateDialog)
647 int topPos, nVisible, selection = itemIndex+2;
649 /* Select the item */
650 XmListDeselectAllItems(listW);
651 XmListSelectPos(listW, selection, updateDialog);
653 /* If the selected item is not visible, scroll the list */
654 XtVaGetValues(listW, XmNtopItemPosition, &topPos, XmNvisibleItemCount,
655 &nVisible, NULL);
656 if (selection < topPos)
657 XmListSetPos(listW, selection);
658 else if (selection >= topPos + nVisible)
659 XmListSetPos(listW, selection - nVisible + 1);