📄 usercmds.c
字号:
int DoNamedBGMenuCmd(WindowInfo *window, const char *itemName){ int i; for (i=0; i<NBGMenuItems; i++) { if (!strcmp(BGMenuItems[i]->name, itemName)) { DoMacro(window, BGMenuItems[i]->cmd, "background menu macro"); return True; } } return False;}/*** Update all of the Shell or Macro menus of all editor windows.*/static void updateMenus(int menuType){ WindowInfo *w; for (w=WindowList; w!=NULL; w=w->next) updateMenu(w, menuType);}/*** Updates either the Shell menu or the Macro menu of "window", depending on** value of "menuType"*/static void updateMenu(WindowInfo *window, int menuType){ Widget btn, menuPane, subPane, newSubPane; int nListItems, n; menuItemRec *f, **itemList; menuTreeItem *menuTree; int i, nTreeEntries, isDefaultLM; char *hierName, *namePtr, *subMenuName, *subSep, *strippedName, *name; /* Fetch the appropriate menu pane and item list for this menu type */ if (menuType == SHELL_CMDS) { menuPane = window->shellMenuPane; itemList = ShellMenuItems; nListItems = NShellMenuItems; } else if (menuType == MACRO_CMDS) { menuPane = window->macroMenuPane; itemList = MacroMenuItems; nListItems = NMacroMenuItems; } else { /* BG_MENU_CMDS */ menuPane = window->bgMenuPane; itemList = BGMenuItems; nListItems = NBGMenuItems; } /* Remove all of the existing user commands from the menu */ removeMenuItems(menuPane); /* Allocate storage for structures to help find sub-menus */ menuTree = (menuTreeItem *)XtMalloc(sizeof(menuTreeItem) * nListItems); nTreeEntries = 0; /* Harmless kludge: undo and redo items are marked specially if found in the background menu, and used to dim/undim with edit menu */ window->bgMenuUndoItem = NULL; window->bgMenuRedoItem = NULL; /* ** Add items to the list, creating hierarchical sub-menus as necessary, ** and skipping items not intended for this language mode */ for (n=0; n<nListItems; n++) { f = itemList[n]; /* Eliminate items meant for other language modes, strip @ sign parts. If the language mode is "*", scan the list for an item with the same name and a language mode specified. If one is found, skip the item in favor of the exact match. */ strippedName = findStripLanguageMode(f->name, window->languageMode, &isDefaultLM); if (strippedName == NULL) continue; /* not a valid entry for the language */ if (isDefaultLM) { for (i=0; i<nListItems; i++) { name = findStripLanguageMode(itemList[i]->name, window->languageMode, &isDefaultLM); if (name!=NULL && !isDefaultLM && !strcmp(name, strippedName)) { XtFree(name); /* item with matching language overrides */ break; } XtFree(name); } if (i != nListItems) { XtFree(strippedName); continue; } } /* create/find sub-menus, stripping off '>' until item name is reached, then create the menu item */ namePtr = strippedName; subPane = menuPane; for (;;) { subSep = strchr(namePtr, '>'); if (subSep == NULL) { btn = createUserMenuItem(subPane, namePtr, f, n, (XtCallbackProc)(menuType == SHELL_CMDS ? shellMenuCB : (menuType == MACRO_CMDS ? macroMenuCB : bgMenuCB)), (XtPointer)window); if (menuType == BG_MENU_CMDS && !strcmp(f->cmd, "undo()\n")) window->bgMenuUndoItem = btn; else if (menuType == BG_MENU_CMDS && !strcmp(f->cmd,"redo()\n")) window->bgMenuRedoItem = btn; UpdateAccelLockPatch(window->splitPane, btn); break; } hierName = copySubstring(strippedName, subSep - strippedName); newSubPane = findInMenuTree(menuTree, nTreeEntries, hierName); if (newSubPane == NULL) { subMenuName = copySubstring(namePtr, subSep - namePtr); newSubPane = createUserSubMenu(subPane, subMenuName); XtFree(subMenuName); menuTree[nTreeEntries].name = hierName; menuTree[nTreeEntries++].menuPane = newSubPane; } else XtFree(hierName); subPane = newSubPane; namePtr = subSep + 1; } XtFree(strippedName); } /* Free the structure used to keep track of sub-menus durring creation */ for (i=0; i<nTreeEntries; i++) XtFree(menuTree[i].name); XtFree((char *)menuTree); /* Set the proper sensitivity of items which may be dimmed */ SetBGMenuUndoSensitivity(window, XtIsSensitive(window->undoItem)); SetBGMenuRedoSensitivity(window, XtIsSensitive(window->redoItem)); DimSelectionDepUserMenuItems(window, window->buffer->primary.selected);}/*** Find the widget corresponding to a hierarchical menu name (a>b>c...)*/static Widget findInMenuTree(menuTreeItem *menuTree, int nTreeEntries, const char *hierName){ int i; for (i=0; i<nTreeEntries; i++) if (!strcmp(hierName, menuTree[i].name)) return menuTree[i].menuPane; return NULL;}static char *copySubstring(const char *string, int length){ char *retStr = XtMalloc(length + 1); strncpy(retStr, string, length); retStr[length] = '\0'; return retStr;}/*** Look for at signs (@) in the string menuItemName, and match them** against the current language mode. If there are no @ signs, just** return an allocated copy of menuItemName. If there are @ signs, match** the following text against languageMode, and return NULL if none match,** or an allocated copy of menuItemName stripped of @ parts. If the** language name is "*", sets isDefaultLM to true.*/static char *findStripLanguageMode(const char *menuItemName, int languageMode, int *isDefaultLM){ char *atPtr, *firstAtPtr, *endPtr; int lmNameLen; atPtr = firstAtPtr = strchr(menuItemName, '@'); *isDefaultLM = False; if (atPtr == NULL) { return XtNewString(menuItemName); } if (!strcmp(atPtr+1, "*")) { /* only language is "*": this is for all but language specific macros */ *isDefaultLM = True; return copySubstring(menuItemName, firstAtPtr-menuItemName); } if (languageMode == PLAIN_LANGUAGE_MODE) return NULL; for (;;) { for(endPtr=atPtr+1; isalnum((unsigned char)*endPtr) || *endPtr=='_' || *endPtr=='-' || *endPtr==' ' || *endPtr=='+' || *endPtr=='$' || *endPtr=='#'; endPtr++); lmNameLen = endPtr-atPtr-1; if (!strncmp(LanguageModeName(languageMode), atPtr+1, lmNameLen) && LanguageModeName(languageMode)[lmNameLen] == '\0') return copySubstring(menuItemName, firstAtPtr-menuItemName); atPtr = strchr(atPtr+1, '@'); if (atPtr == NULL) return NULL; }} static Widget createUserMenuItem(Widget menuPane, char *name, menuItemRec *f, int index, XtCallbackProc cbRtn, XtPointer cbArg){ XmString st1, st2; char accText[MAX_ACCEL_LEN], accKeys[MAX_ACCEL_LEN+5]; Widget btn; generateAcceleratorString(accText, f->modifiers, f->keysym); genAccelEventName(accKeys, f->modifiers, f->keysym); st1=XmStringCreateSimple(name); st2=XmStringCreateSimple(accText); btn = XtVaCreateManagedWidget("cmd", xmPushButtonWidgetClass, menuPane, XmNlabelString, st1, XmNacceleratorText, st2, XmNaccelerator, accKeys, XmNmnemonic, f->mnemonic, XmNuserData, index+10, NULL); XtAddCallback(btn, XmNactivateCallback, cbRtn, cbArg); XmStringFree(st1); XmStringFree(st2); return btn;}/*** Add a user-defined sub-menu to an established pull-down menu, marking** it's userData field with TEMPORARY_MENU_ITEM so it can be found and** removed later if the menu is redefined. Returns the menu pane of the** new sub menu.*/static Widget createUserSubMenu(Widget parent, char *label){ Widget menu; XmString st1; static Arg args[1] = {{XmNuserData, (XtArgVal)TEMPORARY_MENU_ITEM}}; menu = CreatePulldownMenu(parent, "userPulldown", args, 1); XtVaCreateManagedWidget("userCascade", xmCascadeButtonWidgetClass, parent, XmNlabelString, st1=XmStringCreateSimple(label), XmNsubMenuId, menu, XmNuserData, TEMPORARY_MENU_ITEM, NULL); XmStringFree(st1); return menu;}static void removeMenuItems(Widget menuPane){ WidgetList items, itemList; Widget subMenuID; XtPointer userData; int n; Cardinal nItems; /* Fetch the list of children from the menu pane, and make a copy (because the widget alters this list as you delete widgets) */ XtVaGetValues(menuPane, XmNchildren, &itemList, XmNnumChildren, &nItems, NULL); items = (WidgetList)XtMalloc(sizeof(Widget) * nItems); memcpy(items, itemList, sizeof(Widget) * nItems); /* Delete all of the widgets not marked as PERMANENT_MENU_ITEM */ for (n=0; n<(int)nItems; n++) { XtVaGetValues(items[n], XmNuserData, &userData, NULL); if (userData != (XtPointer)PERMANENT_MENU_ITEM) { if (XtClass(items[n]) == xmCascadeButtonWidgetClass) { XtVaGetValues(items[n], XmNsubMenuId, &subMenuID, NULL); removeMenuItems(subMenuID);#if XmVersion < 2000 /* Skipping this creates a memory and server resource leak (though both are reclaimed on window closing). In Motif 2.0 (and beyond?) there is a potential crash during phase 2 widget destruction in "SetCascadeField", and in Motif 1.2 there are free-memory reads. I would really like to be able to destroy this. */ XtDestroyWidget(subMenuID);#endif } else /* remove accel. before destroy or lose it forever */ XtVaSetValues(items[n], XmNaccelerator, NULL, NULL); /* unmanaging before destroying stops parent from displaying */ XtUnmanageChild(items[n]); XtDestroyWidget(items[n]); } } XtFree((char *)items);}static void dismissCB(Widget w, XtPointer clientData, XtPointer callData){ userCmdDialog *ucd = (userCmdDialog *)clientData; /* Mark that there's no longer a (macro, bg, or shell) dialog up */ if (ucd->dialogType == SHELL_CMDS) ShellCmdDialog = NULL; else if (ucd->dialogType == MACRO_CMDS) MacroCmdDialog = NULL; else BGMenuCmdDialog = NULL; /* pop down and destroy the dialog (memory for ucd is freed in the destroy callback) */ XtDestroyWidget(ucd->dlogShell);}static void okCB(Widget w, XtPointer clientData, XtPointer callData){ userCmdDialog *ucd = (userCmdDialog *)clientData; /* Read the dialog fields, and update the menus */ if (!applyDialogChanges(ucd)) return; /* Mark that there's no longer a (macro, bg, or shell) dialog up */ if (ucd->dialogType == SHELL_CMDS) ShellCmdDialog = NULL; else if (ucd->dialogType == MACRO_CMDS) MacroCmdDialog = NULL; else BGMenuCmdDialog = NULL; /* pop down and destroy the dialog (memory for ucd is freed in the destroy callback) */ XtDestroyWidget(ucd->dlogShell);}static void applyCB(Widget w, XtPointer clientData, XtPointer callData){ applyDialogChanges((userCmdDialog *)clientData);}static void checkCB(Widget w, XtPointer clientData, XtPointer callData){ userCmdDialog *ucd = (userCmdDialog *)clientData; if (checkMacro(ucd)) { DialogF(DF_INF, ucd->dlogShell, 1, "Macro", "Macro compiled without error", "Dismiss"); }}static int checkMacro(userCmdDialog *ucd){ menuItemRec *f; f = readDialogFields(ucd, False); if (f == NULL) return False; if (!checkMacroText(f->cmd, ucd->dlogShell, ucd->cmdTextW)) { freeMenuItemRec(f); return False; } return True;}static int checkMacroText(char *macro, Widget errorParent, Widget errFocus){ Program *prog; char *errMsg, *stoppedAt; prog = ParseMacro(macro, &errMsg, &stoppedAt); if (prog == NULL) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -