📄 managedlist.c
字号:
int ManagedListSelectedIndex(Widget listW){ managedListData *ml; XtVaGetValues(listW, XmNuserData, &ml, NULL); return selectedListPosition(ml)-2;}/*** Add a delete-confirmation callback to a managed list. This will be called** when the user presses the Delete button on the managed list. The callback** can put up a dialog, and optionally abort the operation by returning False.*/void AddDeleteConfirmCB(Widget listW, int (*deleteConfirmCB)(int, void *), void *deleteConfirmArg){ managedListData *ml; XtVaGetValues(listW, XmNuserData, &ml, NULL); ml->deleteConfirmCB = deleteConfirmCB; ml->deleteConfirmArg = deleteConfirmArg;}/*** Called on destruction of the list widget*/static void destroyCB(Widget w, XtPointer clientData, XtPointer callData){ /* Free the managed list data structure */ XtFree((char *)clientData);}/*** Button callbacks: deleteCB, copyCB, moveUpCB, moveDownCB*/static void deleteCB(Widget w, XtPointer clientData, XtPointer callData){ managedListData *ml = (managedListData *)clientData; int i, ind, listPos; /* get the selected list position and the item to be deleted */ listPos = selectedListPosition(ml); ind = listPos-2; /* if there's a delete confirmation callback, call it first, and allow it to request that the operation be aborted */ if (ml->deleteConfirmCB != NULL) if (!(*ml->deleteConfirmCB)(ind, ml->deleteConfirmArg)) return; /* free the item and remove it from the list */ (*ml->freeItemCB)(ml->itemList[ind]); for (i=ind; i<*ml->nItems-1; i++) ml->itemList[i] = ml->itemList[i+1]; (*ml->nItems)--; /* update the list widget and move the selection to the previous item in the list and display the fields appropriate for that entry */ updateDialogFromList(ml, ind-1);}static void copyCB(Widget w, XtPointer clientData, XtPointer callData){ managedListData *ml = (managedListData *)clientData; int i, listPos, abort = False; void *item; /* get the selected list position and the item to be copied */ listPos = selectedListPosition(ml); if (listPos == 1) return; /* can't copy "new" */ /* Bring the entry up to date (could result in operation being canceled) */ item = (*ml->getDialogDataCB)(ml->itemList[listPos-2], False, &abort, ml->getDialogDataArg); if (abort) return; if (item != NULL) { (*ml->freeItemCB)(ml->itemList[listPos-2]); ml->itemList[listPos-2] = item; } /* Make a copy by requesting the data again. In case getDialogDataCB() returned a fallback value, the dialog may not be in sync with the internal list. If we _explicitly_ request the data again, we could get an invalid answer. Therefore, we first update the dialog to make sure that we can copy the right data. */ updateDialogFromList(ml, listPos-2); item = (*ml->getDialogDataCB)(ml->itemList[listPos-2], True, &abort, ml->getDialogDataArg); if (abort) return; /* add the item to the item list */ for (i= *ml->nItems; i>=listPos; i--) ml->itemList[i] = ml->itemList[i-1]; ml->itemList[listPos-1] = item; (*ml->nItems)++; /* redisplay the list widget and select the new item */ updateDialogFromList(ml, listPos-1);}static void moveUpCB(Widget w, XtPointer clientData, XtPointer callData){ managedListData *ml = (managedListData *)clientData; int ind, listPos; void *temp; /* get the item index currently selected in the menu item list */ listPos = selectedListPosition(ml); ind = listPos-2; /* Bring the item up to date with the dialog fields (It would be better if this could be avoided, because user errors will be flagged here, but it's not worth re-writing everything for such a trivial point) */ if (!incorporateDialogData(ml, ml->lastSelection, False)) return; /* shuffle the item up in the menu item list */ temp = ml->itemList[ind]; ml->itemList[ind] = ml->itemList[ind-1]; ml->itemList[ind-1] = temp; /* update the list widget and keep the selection on moved item */ updateDialogFromList(ml, ind-1);}static void moveDownCB(Widget w, XtPointer clientData, XtPointer callData){ managedListData *ml = (managedListData *)clientData; int ind, listPos; void *temp; /* get the item index currently selected in the menu item list */ listPos = selectedListPosition(ml); ind = listPos-2; /* Bring the item up to date with the dialog fields (I wish this could be avoided) */ if (!incorporateDialogData(ml, ml->lastSelection, False)) return; /* shuffle the item down in the menu item list */ temp = ml->itemList[ind]; ml->itemList[ind] = ml->itemList[ind+1]; ml->itemList[ind+1] = temp; /* update the list widget and keep the selection on moved item */ updateDialogFromList(ml, ind+1);}/*** Called when the user clicks on an item in the list widget*/static void listSelectionCB(Widget w, XtPointer clientData, XtPointer callData){ managedListData *ml = (managedListData *)clientData; int ind, listPos = ((XmListCallbackStruct *)callData)->item_position; /* Save the current dialog fields before overwriting them. If there's an error, force the user to go back to the old selection and fix it before proceeding */ if (ml->getDialogDataCB != NULL && ml->lastSelection != 0) { if (!incorporateDialogData(ml, ml->lastSelection, False)) { XmListDeselectAllItems(ml->listW); XmListSelectPos(ml->listW, ml->lastSelection, False); return; } /* reselect item because incorporateDialogData can alter selection */ selectItem(ml->listW, listPos-2, False); } ml->lastSelection = listPos; /* Dim or un-dim buttons at bottom of dialog based on whether the selected item is a menu entry, or "New" */ if (listPos == 1) { XtSetSensitive(ml->copyBtn, False); XtSetSensitive(ml->deleteBtn, False); XtSetSensitive(ml->moveUpBtn, False); XtSetSensitive(ml->moveDownBtn, False); } else { XtSetSensitive(ml->copyBtn, True); XtSetSensitive(ml->deleteBtn, True); XtSetSensitive(ml->moveUpBtn, listPos != 2); XtSetSensitive(ml->moveDownBtn, listPos != *ml->nItems+1); } /* get the index of the item currently selected in the item list */ ind = listPos - 2; /* tell the caller to show the new item */ if (ml->setDialogDataCB != NULL) (*ml->setDialogDataCB)(listPos==1 ? NULL : ml->itemList[ind], ml->setDialogDataArg);}/*** Incorporate the current contents of the dialog fields into the list** being managed, and if necessary change the display in the list widget.** The data is obtained by calling the getDialogDataCB callback, which** is allowed to reject whatever request triggered the update. If the** request is rejected, the return value from this function will be False.*/static int incorporateDialogData(managedListData *ml, int listPos, int explicit){ int abort = False; void *item; /* Get the current contents of the dialog fields. Callback will set abort to True if canceled */ item = (*ml->getDialogDataCB)(listPos == 1 ? NULL : ml->itemList[ listPos-2], explicit, &abort, ml->getDialogDataArg); if (abort) return False; if (item == NULL) /* don't modify if fields are empty */ return True; /* If the item is "new" add a new entry to the list, otherwise, modify the entry with the text fields from the dialog */ if (listPos == 1) { ml->itemList[(*ml->nItems)++] = item; updateDialogFromList(ml, *ml->nItems - 1); } else { (*ml->freeItemCB)(ml->itemList[listPos-2]); ml->itemList[listPos-2] = item; updateListWidgetItem(ml, listPos); } return True;}/*** Update the list widget to reflect the current contents of the managed item** list, set the item that should now be highlighted, and call getDisplayed** on the newly selected item to fill in the dialog fields.*/static void updateDialogFromList(managedListData *ml, int selection){ int i; XmString *stringTable; /* On many systems under Motif 1.1 the list widget can't handle items being changed while anything is selected! */ XmListDeselectAllItems(ml->listW); /* Fill in the list widget with the names from the item list */ stringTable = (XmString *)XtMalloc(sizeof(XmString) * (*ml->nItems+1)); stringTable[0] = XmStringCreateSimple("New"); for (i=0; i < *ml->nItems; i++) stringTable[i+1] = XmStringCreateSimple(*(char **)ml->itemList[i]); XtVaSetValues(ml->listW, XmNitems, stringTable, XmNitemCount, *ml->nItems+1, NULL); for (i=0; i < *ml->nItems+1; i++) XmStringFree(stringTable[i]); XtFree((char *)stringTable); /* Select the requested item (indirectly filling in the dialog fields), but don't trigger an update of the last selected item from the current dialog fields */ ml->lastSelection = 0; selectItem(ml->listW, selection, True);}/*** Update one item of the managed list widget to reflect the current contents** of the managed item list.*/static void updateListWidgetItem(managedListData *ml, int listPos){ int savedPos; XmString newString[1]; /* save the current selected position (Motif sometimes does stupid things to the selection when a change is made, like selecting the new item if it matches the name of currently selected one) */ savedPos = selectedListPosition(ml); XmListDeselectAllItems(ml->listW); /* update the list */ newString[0] = XmStringCreateSimple(*(char **)ml->itemList[listPos-2]); XmListReplaceItemsPos(ml->listW, newString, 1, listPos); XmStringFree(newString[0]); /* restore the selected position */ XmListSelectPos(ml->listW, savedPos, False);}/*** Get the position of the selection in the menu item list widget*/static int selectedListPosition(managedListData *ml){ int listPos; int *posList = NULL, posCount = 0; if (!XmListGetSelectedPos(ml->listW, &posList, &posCount)) { fprintf(stderr, "Internal error (nothing selected)"); return 1; } listPos = *posList; XtFree((char *)posList); if (listPos < 1 || listPos > *ml->nItems+1) { fprintf(stderr, "Internal error (XmList bad value)"); return 1; } return listPos;}/*** Select an item in the list given the list (array) index value.** If updateDialog is True, trigger a complete dialog update, which** could potentially reject the change.*/static void selectItem(Widget listW, int itemIndex, int updateDialog){ int topPos, nVisible, selection = itemIndex+2; /* Select the item */ XmListDeselectAllItems(listW); XmListSelectPos(listW, selection, updateDialog); /* If the selected item is not visible, scroll the list */ XtVaGetValues(listW, XmNtopItemPosition, &topPos, XmNvisibleItemCount, &nVisible, NULL); if (selection < topPos) XmListSetPos(listW, selection); else if (selection >= topPos + nVisible) XmListSetPos(listW, selection - nVisible + 1);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -